6.7.3-rc1 review
Subsystems (6)
Greg Kroah-Hartman
maintainerPATCH 127/346 serial: sc16is7xx: improve regmap debugfs by using one regmap per port
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hugo Villeneuve <[email protected]>
commit 3837a0379533aabb9e4483677077479f7c6aa910 upstream.
With this current driver regmap implementation, it is hard to make sense of the register addresses displayed using the regmap debugfs interface, because they do not correspond to the actual register addresses documented in the datasheet. For example, register 1 is displayed as registers 04 thru 07:
$ cat /sys/kernel/debug/regmap/spi0.0/registers 04: 10 -> Port 0, register offset 1 05: 10 -> Port 1, register offset 1 06: 00 -> Port 2, register offset 1 -> invalid 07: 00 -> port 3, register offset 1 -> invalid ...
The reason is that bits 0 and 1 of the register address correspond to the channel (port) bits, so the register address itself starts at bit 2, and we must 'mentally' shift each register address by 2 bits to get its real address/offset.
Also, only channels 0 and 1 are supported by the chip, so channel mask combinations of 10b and 11b are invalid, and the display of these registers is useless.
This patch adds a separate regmap configuration for each port, similar to what is done in the max310x driver, so that register addresses displayed match the register addresses in the chip datasheet. Also, each port now has its own debugfs entry.
Example with new regmap implementation:
$ cat /sys/kernel/debug/regmap/spi0.0-port0/registers 1: 10 2: 01 3: 00 ...
$ cat /sys/kernel/debug/regmap/spi0.0-port1/registers 1: 10 2: 01 3: 00
As an added bonus, this also simplifies some operations (read/write/modify) because it is no longer necessary to manually shift register addresses.
--- drivers/tty/serial/sc16is7xx.c | 143 +++++++++++++++++++++++------------------ 1 file changed, 81 insertions(+), 62 deletions(-)
drivers/tty/serial/sc16is7xx.c +81 -62
@@ -301,8 +301,8 @@/* Misc definitions */ +#define SC16IS7XX_SPI_READ_BIT BIT(7)#define SC16IS7XX_FIFO_SIZE (64) -#define SC16IS7XX_REG_SHIFT 2#define SC16IS7XX_GPIOS_PER_BANK 4struct sc16is7xx_devtype {
@@ -324,6 +324,7 @@ struct sc16is7xx_one_config {struct sc16is7xx_one {struct uart_port port;u8 line; +struct regmap *regmap;struct kthread_work tx_work;struct kthread_work reg_work;struct kthread_delayed_work ms_work;
@@ -361,48 +362,37 @@ static void sc16is7xx_stop_tx(struct uar#define to_sc16is7xx_one (p,e) ((container_of((p), struct sc16is7xx_one, e))) -static int sc16is7xx_line (struct uart_port *port) -{ -struct sc16is7xx_one *one =to_sc16is7xx_one (port, port); - -return one->line; -} -static u8 sc16is7xx_port_read (struct uart_port *port,u8 reg) { -struct sc16is7xx_port *s =dev_get_drvdata (port->dev); +struct sc16is7xx_one *one =to_sc16is7xx_one (port, port);unsigned int val =0 ; -const u8 line =sc16is7xx_line (port); -regmap_read (s->regmap, (reg <<SC16IS7XX_REG_SHIFT ) | line, &val); +regmap_read (one->regmap, reg, &val);return val; }static void sc16is7xx_port_write (struct uart_port *port,u8 reg,u8 val) { -struct sc16is7xx_port *s =dev_get_drvdata (port->dev); -const u8 line =sc16is7xx_line (port); +struct sc16is7xx_one *one =to_sc16is7xx_one (port, port); -regmap_write (s->regmap, (reg <<SC16IS7XX_REG_SHIFT ) | line, val); +regmap_write (one->regmap, reg, val); }static void sc16is7xx_fifo_read (struct uart_port *port,unsigned int rxlen) {struct sc16is7xx_port *s =dev_get_drvdata (port->dev); -const u8 line =sc16is7xx_line (port); -u8 addr = (SC16IS7XX_RHR_REG <<SC16IS7XX_REG_SHIFT ) | line; +struct sc16is7xx_one *one =to_sc16is7xx_one (port, port); -regcache_cache_bypass (s->regmap, true); -regmap_raw_read (s->regmap, addr, s->buf, rxlen); -regcache_cache_bypass (s->regmap, false); +regcache_cache_bypass (one->regmap, true); +regmap_raw_read (one->regmap,SC16IS7XX_RHR_REG , s->buf, rxlen); +regcache_cache_bypass (one->regmap, false); }static void sc16is7xx_fifo_write (struct uart_port *port,u8 to_send) {struct sc16is7xx_port *s =dev_get_drvdata (port->dev); -const u8 line =sc16is7xx_line (port); -u8 addr = (SC16IS7XX_THR_REG <<SC16IS7XX_REG_SHIFT ) | line; +struct sc16is7xx_one *one =to_sc16is7xx_one (port, port);/* * Don't send zero-length data, at least on SPI it confuses the chip
@@ -411,19 +401,17 @@ static void sc16is7xx_fifo_write(structif (unlikely (!to_send))return ; -regcache_cache_bypass (s->regmap, true); -regmap_raw_write (s->regmap, addr, s->buf, to_send); -regcache_cache_bypass (s->regmap, false); +regcache_cache_bypass (one->regmap, true); +regmap_raw_write (one->regmap,SC16IS7XX_THR_REG , s->buf, to_send); +regcache_cache_bypass (one->regmap, false); }static void sc16is7xx_port_update (struct uart_port *port,u8 reg,u8 mask,u8 val) { -struct sc16is7xx_port *s =dev_get_drvdata (port->dev); -const u8 line =sc16is7xx_line (port); +struct sc16is7xx_one *one =to_sc16is7xx_one (port, port); -regmap_update_bits (s->regmap, (reg <<SC16IS7XX_REG_SHIFT ) | line, - mask, val); +regmap_update_bits (one->regmap, reg, mask, val); }static int sc16is7xx_alloc_line (void )
@@ -478,7 +466,7 @@ static const struct sc16is7xx_devtype scstatic bool sc16is7xx_regmap_volatile (struct device *dev,unsigned int reg) { -switch (reg >>SC16IS7XX_REG_SHIFT ) { +switch (reg) {case SC16IS7XX_RHR_REG :case SC16IS7XX_IIR_REG :case SC16IS7XX_LSR_REG :
@@ -497,7 +485,7 @@ static bool sc16is7xx_regmap_volatile(ststatic bool sc16is7xx_regmap_precious (struct device *dev,unsigned int reg) { -switch (reg >>SC16IS7XX_REG_SHIFT ) { +switch (reg) {case SC16IS7XX_RHR_REG :return true;default :
@@ -510,6 +498,7 @@ static bool sc16is7xx_regmap_precious(ststatic int sc16is7xx_set_baud (struct uart_port *port,int baud) {struct sc16is7xx_port *s =dev_get_drvdata (port->dev); +struct sc16is7xx_one *one =to_sc16is7xx_one (port, port);u8 lcr;u8 prescaler =0 ;unsigned long clk = port->uartclk, div = clk /16 / baud;
@@ -541,12 +530,12 @@ static int sc16is7xx_set_baud(struct uar SC16IS7XX_LCR_CONF_MODE_B);/* Enable enhanced features */ -regcache_cache_bypass (s->regmap, true); +regcache_cache_bypass (one->regmap, true);sc16is7xx_port_update (port,SC16IS7XX_EFR_REG ,SC16IS7XX_EFR_ENABLE_BIT ,SC16IS7XX_EFR_ENABLE_BIT ); -regcache_cache_bypass (s->regmap, false); +regcache_cache_bypass (one->regmap, false);/* Put LCR back to the normal mode */ sc16is7xx_port_write (port,SC16IS7XX_LCR_REG , lcr);
@@ -562,10 +551,10 @@ static int sc16is7xx_set_baud(struct uar SC16IS7XX_LCR_CONF_MODE_A);/* Write the new divisor */ -regcache_cache_bypass (s->regmap, true); +regcache_cache_bypass (one->regmap, true);sc16is7xx_port_write (port,SC16IS7XX_DLH_REG , div /256 );sc16is7xx_port_write (port,SC16IS7XX_DLL_REG , div %256 ); -regcache_cache_bypass (s->regmap, false); +regcache_cache_bypass (one->regmap, false);/* Put LCR back to the normal mode */ sc16is7xx_port_write (port,SC16IS7XX_LCR_REG , lcr);
@@ -1091,7 +1080,7 @@ static void sc16is7xx_set_termios(struct SC16IS7XX_LCR_CONF_MODE_B);/* Configure flow control */ -regcache_cache_bypass (s->regmap, true); +regcache_cache_bypass (one->regmap, true);sc16is7xx_port_write (port,SC16IS7XX_XON1_REG , termios->c_cc[VSTART ]);sc16is7xx_port_write (port,SC16IS7XX_XOFF1_REG , termios->c_cc[VSTOP ]);
@@ -1110,7 +1099,7 @@ static void sc16is7xx_set_termios(structSC16IS7XX_EFR_REG ,SC16IS7XX_EFR_FLOWCTRL_BITS , flow); -regcache_cache_bypass (s->regmap, false); +regcache_cache_bypass (one->regmap, false);/* Update LCR register */ sc16is7xx_port_write (port,SC16IS7XX_LCR_REG , lcr);
@@ -1161,7 +1150,6 @@ static int sc16is7xx_config_rs485(structstatic int sc16is7xx_startup (struct uart_port *port) {struct sc16is7xx_one *one =to_sc16is7xx_one (port, port); -struct sc16is7xx_port *s =dev_get_drvdata (port->dev);unsigned int val;unsigned long flags;
@@ -1178,7 +1166,7 @@ static int sc16is7xx_startup(struct uartsc16is7xx_port_write (port,SC16IS7XX_LCR_REG ,SC16IS7XX_LCR_CONF_MODE_B ); -regcache_cache_bypass (s->regmap, true); +regcache_cache_bypass (one->regmap, true);/* Enable write access to enhanced features and internal clock div */ sc16is7xx_port_update(port, SC16IS7XX_EFR_REG,
@@ -1196,7 +1184,7 @@ static int sc16is7xx_startup(struct uartSC16IS7XX_TCR_RX_RESUME (24 ) | SC16IS7XX_TCR_RX_HALT(48)); -regcache_cache_bypass (s->regmap, false); +regcache_cache_bypass (one->regmap, false);/* Now, initialize the UART */ sc16is7xx_port_write (port,SC16IS7XX_LCR_REG ,SC16IS7XX_LCR_WORD_LEN_8 );
@@ -1477,7 +1465,7 @@ static int sc16is7xx_setup_mctrl_ports(sif (s->mctrl_mask)regmap_update_bits ( s->regmap, -SC16IS7XX_IOCONTROL_REG <<SC16IS7XX_REG_SHIFT , +SC16IS7XX_IOCONTROL_REG ,SC16IS7XX_IOCONTROL_MODEM_A_BIT |SC16IS7XX_IOCONTROL_MODEM_B_BIT , s->mctrl_mask);
@@ -1492,7 +1480,7 @@ static const struct serial_rs485 sc16is7static int sc16is7xx_probe (struct device *dev,const struct sc16is7xx_devtype *devtype, -struct regmap *regmap,int irq) +struct regmap *regmaps[],int irq) {unsigned long freq =0 , *pfreq =dev_get_platdata (dev);unsigned int val;
@@ -1500,16 +1488,16 @@ static int sc16is7xx_probe(struct deviceint i, ret;struct sc16is7xx_port *s; -if (IS_ERR (regmap)) -return PTR_ERR (regmap); +for (i =0 ; i < devtype->nr_uart; i++) +if (IS_ERR (regmaps[i])) +return PTR_ERR (regmaps[i]);/* * This device does not have an identification register that would * tell us if we are really connected to the correct device. * The best we can do is to check if communication is at all possible. */ - ret =regmap_read (regmap, -SC16IS7XX_LSR_REG <<SC16IS7XX_REG_SHIFT , &val); + ret =regmap_read (regmaps[0 ],SC16IS7XX_LSR_REG , &val);if (ret <0 )return -EPROBE_DEFER ;
@@ -1543,7 +1531,7 @@ static int sc16is7xx_probe(struct devicereturn -EINVAL ; } - s->regmap = regmap; + s->regmap = regmaps[0 ]; s->devtype = devtype;dev_set_drvdata (dev, s);mutex_init (&s->efr_lock);
@@ -1558,8 +1546,8 @@ static int sc16is7xx_probe(struct devicesched_set_fifo (s->kworker_task);/* reset device, purging any pending irq / data */ -regmap_write (s->regmap,SC16IS7XX_IOCONTROL_REG <<SC16IS7XX_REG_SHIFT , -SC16IS7XX_IOCONTROL_SRESET_BIT ); +regmap_write (s->regmap,SC16IS7XX_IOCONTROL_REG , +SC16IS7XX_IOCONTROL_SRESET_BIT );for (i =0 ; i < devtype->nr_uart; ++i) { s->p[i].line = i;
@@ -1583,6 +1571,7 @@ static int sc16is7xx_probe(struct device s->p[i].port.ops = &sc16is7xx_ops; s->p[i].old_mctrl =0 ; s->p[i].port.line =sc16is7xx_alloc_line (); + s->p[i].regmap = regmaps[i];if (s->p[i].port.line >=SC16IS7XX_MAX_DEVS ) { ret = -ENOMEM ;
@@ -1611,13 +1600,13 @@ static int sc16is7xx_probe(struct devicesc16is7xx_port_write (&s->p[i].port,SC16IS7XX_LCR_REG ,SC16IS7XX_LCR_CONF_MODE_B ); -regcache_cache_bypass (s->regmap, true); +regcache_cache_bypass (regmaps[i], true);/* Enable write access to enhanced features */ sc16is7xx_port_write (&s->p[i].port,SC16IS7XX_EFR_REG ,SC16IS7XX_EFR_ENABLE_BIT ); -regcache_cache_bypass (s->regmap, false); +regcache_cache_bypass (regmaps[i], false);/* Restore access to general registers */ sc16is7xx_port_write (&s->p[i].port,SC16IS7XX_LCR_REG ,0x00 );
@@ -1711,19 +1700,36 @@ static const struct of_device_id __maybeMODULE_DEVICE_TABLE (of, sc16is7xx_dt_ids);static struct regmap_config regcfg = { - .reg_bits =7 , - .pad_bits =1 , + .reg_bits =5 , + .pad_bits =3 , .val_bits =8 , .cache_type =REGCACHE_RBTREE , .volatile_reg = sc16is7xx_regmap_volatile, .precious_reg = sc16is7xx_regmap_precious, + .max_register =SC16IS7XX_EFCR_REG , }; +static const char *sc16is7xx_regmap_name (unsigned int port_id) +{ +static char buf[6 ]; + +snprintf (buf,sizeof (buf),"port%d" , port_id); + +return buf; +} + +static unsigned int sc16is7xx_regmap_port_mask (unsigned int port_id) +{ +/* CH1,CH0 are at bits 2:1. */ +return port_id <<1 ; +} +#ifdef CONFIG_SERIAL_SC16IS7XX_SPI static int sc16is7xx_spi_probe (struct spi_device *spi) {const struct sc16is7xx_devtype *devtype; -struct regmap *regmap; +struct regmap *regmaps[2 ]; +unsigned int i;int ret;/* Setup SPI bus */
@@ -1748,11 +1754,20 @@ static int sc16is7xx_spi_probe(struct sp devtype = (struct sc16is7xx_devtype *)id_entry->driver_data; } - regcfg.max_register = (0xf <<SC16IS7XX_REG_SHIFT ) | - (devtype->nr_uart -1 ); - regmap =devm_regmap_init_spi (spi, ®cfg); +for (i =0 ; i < devtype->nr_uart; i++) { + regcfg.name =sc16is7xx_regmap_name (i); +/* +* If read_flag_mask is 0, the regmap code sets it to a default +* of 0x80. Since we specify our own mask, we must add the READ +* bit ourselves: +*/ + regcfg.read_flag_mask =sc16is7xx_regmap_port_mask (i) | +SC16IS7XX_SPI_READ_BIT ; + regcfg.write_flag_mask =sc16is7xx_regmap_port_mask (i); + regmaps[i] =devm_regmap_init_spi (spi, ®cfg); + } -return sc16is7xx_probe (&spi->dev, devtype, regmap, spi->irq); +return sc16is7xx_probe (&spi->dev, devtype, regmaps, spi->irq); }static void sc16is7xx_spi_remove (struct spi_device *spi)
@@ -1791,7 +1806,8 @@ static int sc16is7xx_i2c_probe(struct i2 {const struct i2c_device_id *id =i2c_client_get_device_id (i2c);const struct sc16is7xx_devtype *devtype; -struct regmap *regmap; +struct regmap *regmaps[2 ]; +unsigned int i;if (i2c->dev.of_node) { devtype =device_get_match_data (&i2c->dev);
@@ -1801,11 +1817,14 @@ static int sc16is7xx_i2c_probe(struct i2 devtype = (struct sc16is7xx_devtype *)id->driver_data; } - regcfg.max_register = (0xf <<SC16IS7XX_REG_SHIFT ) | - (devtype->nr_uart -1 ); - regmap =devm_regmap_init_i2c (i2c, ®cfg); +for (i =0 ; i < devtype->nr_uart; i++) { + regcfg.name =sc16is7xx_regmap_name (i); + regcfg.read_flag_mask =sc16is7xx_regmap_port_mask (i); + regcfg.write_flag_mask =sc16is7xx_regmap_port_mask (i); + regmaps[i] =devm_regmap_init_i2c (i2c, ®cfg); + } -return sc16is7xx_probe (&i2c->dev, devtype, regmap, i2c->irq); +return sc16is7xx_probe (&i2c->dev, devtype, regmaps, i2c->irq); }static void sc16is7xx_i2c_remove (struct i2c_client *client)
Greg Kroah-Hartman
maintainerPATCH 128/346 serial: sc16is7xx: remove wasteful static buffer in sc16is7xx_regmap_name()
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hugo Villeneuve <[email protected]>
commit 6bcab3c8acc88e265c570dea969fd04f137c8a4c upstream.
Using a static buffer inside sc16is7xx_regmap_name() was a convenient and simple way to set the regmap name without having to allocate and free a buffer each time it is called. The drawback is that the static buffer wastes memory for nothing once regmap is fully initialized.
Remove static buffer and use constant strings instead.
This also avoids a truncation warning when using "%d" or "%u" in snprintf which was flagged by kernel test robot.
--- drivers/tty/serial/sc16is7xx.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-)
drivers/tty/serial/sc16is7xx.c +8 -6
@@ -1709,13 +1709,15 @@ static struct regmap_config regcfg = { .max_register = SC16IS7XX_EFCR_REG, }; -static const char *sc16is7xx_regmap_name (unsigned int port_id) +static const char *sc16is7xx_regmap_name (u8 port_id) { -static char buf[6 ]; - -snprintf (buf,sizeof (buf),"port%d" , port_id); - -return buf; +switch (port_id) { +case 0 :return "port0" ; +case 1 :return "port1" ; +default : +WARN_ON (true); +return NULL ; + } }static unsigned int sc16is7xx_regmap_port_mask (unsigned int port_id)
Greg Kroah-Hartman
maintainerPATCH 129/346 serial: sc16is7xx: remove global regmap from struct sc16is7xx_port
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hugo Villeneuve <[email protected]>
commit f6959c5217bd799bcb770b95d3c09b3244e175c6 upstream.
Remove global struct regmap so that it is more obvious that this regmap is to be used only in the probe function.
Also add a comment to that effect in probe function.
--- drivers/tty/serial/sc16is7xx.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)
drivers/tty/serial/sc16is7xx.c +9 -6
@@ -335,7 +335,6 @@ struct sc16is7xx_one {struct sc16is7xx_port {const struct sc16is7xx_devtype *devtype; -struct regmap *regmap;struct clk *clk;#ifdef CONFIG_GPIOLIB struct gpio_chip gpio;
@@ -1435,7 +1434,8 @@ static void sc16is7xx_setup_irda_ports(s/* * Configure ports designated to operate as modem control lines. */ -static int sc16is7xx_setup_mctrl_ports (struct sc16is7xx_port *s) +static int sc16is7xx_setup_mctrl_ports (struct sc16is7xx_port *s, +struct regmap *regmap) {int i;int ret;
@@ -1464,7 +1464,7 @@ static int sc16is7xx_setup_mctrl_ports(sif (s->mctrl_mask)regmap_update_bits ( - s->regmap, + regmap,SC16IS7XX_IOCONTROL_REG ,SC16IS7XX_IOCONTROL_MODEM_A_BIT |SC16IS7XX_IOCONTROL_MODEM_B_BIT , s->mctrl_mask);
@@ -1496,6 +1496,10 @@ static int sc16is7xx_probe(struct device* This device does not have an identification register that would * tell us if we are really connected to the correct device. * The best we can do is to check if communication is at all possible. +* +* Note: regmap[0] is used in the probe function to access registers +* common to all channels/ports, as it is guaranteed to be present on +* all variants. */ ret =regmap_read (regmaps[0 ],SC16IS7XX_LSR_REG , &val);if (ret <0 )
@@ -1531,7 +1535,6 @@ static int sc16is7xx_probe(struct devicereturn -EINVAL ; } - s->regmap = regmaps[0 ]; s->devtype = devtype;dev_set_drvdata (dev, s);mutex_init (&s->efr_lock);
@@ -1546,7 +1549,7 @@ static int sc16is7xx_probe(struct devicesched_set_fifo (s->kworker_task);/* reset device, purging any pending irq / data */ -regmap_write (s->regmap,SC16IS7XX_IOCONTROL_REG , +regmap_write (regmaps[0 ],SC16IS7XX_IOCONTROL_REG ,SC16IS7XX_IOCONTROL_SRESET_BIT );for (i =0 ; i < devtype->nr_uart; ++i) {
@@ -1617,7 +1620,7 @@ static int sc16is7xx_probe(struct devicesc16is7xx_setup_irda_ports (s); - ret =sc16is7xx_setup_mctrl_ports (s); + ret =sc16is7xx_setup_mctrl_ports (s, regmaps[0 ]);if (ret) goto out_ports;
Greg Kroah-Hartman
maintainerPATCH 130/346 serial: sc16is7xx: remove unused line structure member
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hugo Villeneuve <[email protected]>
commit 41a308cbedb2a68a6831f0f2e992e296c4b8aff0 upstream.
Now that the driver has been converted to use one regmap per port, the line structure member is no longer used, so remove it.
--- drivers/tty/serial/sc16is7xx.c | 2 -- 1 file changed, 2 deletions(-)
drivers/tty/serial/sc16is7xx.c +0 -2
@@ -323,7 +323,6 @@ struct sc16is7xx_one_config {struct sc16is7xx_one {struct uart_port port; -u8 line;struct regmap *regmap;struct kthread_work tx_work;struct kthread_work reg_work;
@@ -1553,7 +1552,6 @@ static int sc16is7xx_probe(struct device SC16IS7XX_IOCONTROL_SRESET_BIT);for (i =0 ; i < devtype->nr_uart; ++i) { - s->p[i].line = i;/* Initialize port data */ s->p[i].port.dev = dev; s->p[i].port.irq = irq;
Greg Kroah-Hartman
maintainerPATCH 131/346 serial: sc16is7xx: change EFR lock to operate on each channels
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hugo Villeneuve <[email protected]>
commit 4409df5866b7ff7686ba27e449ca97a92ee063c9 upstream.
Now that the driver has been converted to use one regmap per port, change efr locking to operate on a channel basis instead of on the whole IC.
--- drivers/tty/serial/sc16is7xx.c | 49 +++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 23 deletions(-)
drivers/tty/serial/sc16is7xx.c +26 -23
@@ -324,6 +324,7 @@ struct sc16is7xx_one_config {struct sc16is7xx_one {struct uart_port port;struct regmap *regmap; +struct mutex efr_lock;/* EFR registers access */ struct kthread_work tx_work;struct kthread_work reg_work;struct kthread_delayed_work ms_work;
@@ -343,7 +344,6 @@ struct sc16is7xx_port {unsigned char buf[SC16IS7XX_FIFO_SIZE ];struct kthread_worker kworker;struct task_struct *kworker_task; -struct mutex efr_lock;struct sc16is7xx_one p[]; };
@@ -495,7 +495,6 @@ static bool sc16is7xx_regmap_precious(ststatic int sc16is7xx_set_baud (struct uart_port *port,int baud) { -struct sc16is7xx_port *s =dev_get_drvdata (port->dev);struct sc16is7xx_one *one =to_sc16is7xx_one (port, port);u8 lcr;u8 prescaler =0 ;
@@ -519,7 +518,7 @@ static int sc16is7xx_set_baud(struct uar* because the bulk of the interrupt processing is run as a workqueue * job in thread context. */ -mutex_lock (&s->efr_lock); +mutex_lock (&one->efr_lock); lcr =sc16is7xx_port_read (port,SC16IS7XX_LCR_REG );
@@ -538,7 +537,7 @@ static int sc16is7xx_set_baud(struct uar/* Put LCR back to the normal mode */ sc16is7xx_port_write (port,SC16IS7XX_LCR_REG , lcr); -mutex_unlock (&s->efr_lock); +mutex_unlock (&one->efr_lock); sc16is7xx_port_update(port, SC16IS7XX_MCR_REG, SC16IS7XX_MCR_CLKSEL_BIT,
@@ -706,11 +705,10 @@ static unsigned int sc16is7xx_get_hwmctrstatic void sc16is7xx_update_mlines (struct sc16is7xx_one *one) {struct uart_port *port = &one->port; -struct sc16is7xx_port *s =dev_get_drvdata (port->dev);unsigned long flags;unsigned int status, changed; -lockdep_assert_held_once (&s->efr_lock); +lockdep_assert_held_once (&one->efr_lock); status =sc16is7xx_get_hwmctrl (port); changed = status ^ one->old_mctrl;
@@ -736,15 +734,20 @@ static void sc16is7xx_update_mlines(strustatic bool sc16is7xx_port_irq (struct sc16is7xx_port *s,int portno) { +bool rc = true;struct uart_port *port = &s->p[portno].port; +struct sc16is7xx_one *one =to_sc16is7xx_one (port, port); + +mutex_lock (&one->efr_lock); do { unsigned int iir, rxlen; - struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG); - if (iir & SC16IS7XX_IIR_NO_INT_BIT) - return false; + if (iir & SC16IS7XX_IIR_NO_INT_BIT) { + rc = false; + goto out_port_irq; + } iir &= SC16IS7XX_IIR_ID_MASK;
@@ -784,15 +787,17 @@ static bool sc16is7xx_port_irq(struct scbreak ; } }while (0 ); -return true; + +out_port_irq: +mutex_unlock (&one->efr_lock); + +return rc; }static irqreturn_t sc16is7xx_irq (int irq,void *dev_id) {struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id; -mutex_lock (&s->efr_lock); -while (1 ) {bool keep_polling = false;int i;
@@ -803,24 +808,22 @@ static irqreturn_t sc16is7xx_irq(int irqbreak ; } -mutex_unlock (&s->efr_lock); -return IRQ_HANDLED ; }static void sc16is7xx_tx_proc (struct kthread_work *ws) {struct uart_port *port = &(to_sc16is7xx_one (ws, tx_work)->port); -struct sc16is7xx_port *s =dev_get_drvdata (port->dev); +struct sc16is7xx_one *one =to_sc16is7xx_one (port, port);unsigned long flags;if ((port->rs485.flags &SER_RS485_ENABLED ) && (port->rs485.delay_rts_before_send >0 ))msleep (port->rs485.delay_rts_before_send); -mutex_lock (&s->efr_lock); +mutex_lock (&one->efr_lock);sc16is7xx_handle_tx (port); -mutex_unlock (&s->efr_lock); +mutex_unlock (&one->efr_lock);uart_port_lock_irqsave (port, &flags);sc16is7xx_ier_set (port,SC16IS7XX_IER_THRI_BIT );
@@ -927,9 +930,9 @@ static void sc16is7xx_ms_proc(struct kthstruct sc16is7xx_port *s =dev_get_drvdata (one->port.dev);if (one->port.state) { -mutex_lock (&s->efr_lock); +mutex_lock (&one->efr_lock);sc16is7xx_update_mlines (one); -mutex_unlock (&s->efr_lock); +mutex_unlock (&one->efr_lock);kthread_queue_delayed_work (&s->kworker, &one->ms_work,HZ ); }
@@ -1013,7 +1016,6 @@ static void sc16is7xx_set_termios(structstruct ktermios *termios, const struct ktermios *old) { - struct sc16is7xx_port *s = dev_get_drvdata(port->dev); struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);unsigned int lcr, flow =0 ;int baud;
@@ -1072,7 +1074,7 @@ static void sc16is7xx_set_termios(struct port->ignore_status_mask |=SC16IS7XX_LSR_BRK_ERROR_MASK ;/* As above, claim the mutex while accessing the EFR. */ -mutex_lock (&s->efr_lock); +mutex_lock (&one->efr_lock);sc16is7xx_port_write (port,SC16IS7XX_LCR_REG ,SC16IS7XX_LCR_CONF_MODE_B );
@@ -1102,7 +1104,7 @@ static void sc16is7xx_set_termios(struct/* Update LCR register */ sc16is7xx_port_write (port,SC16IS7XX_LCR_REG , lcr); -mutex_unlock (&s->efr_lock); +mutex_unlock (&one->efr_lock);/* Get baud rate generator configuration */ baud = uart_get_baud_rate(port, termios, old,
@@ -1536,7 +1538,6 @@ static int sc16is7xx_probe(struct device s->devtype = devtype;dev_set_drvdata (dev, s); -mutex_init (&s->efr_lock);kthread_init_worker (&s->kworker); s->kworker_task = kthread_run(kthread_worker_fn, &s->kworker,
@@ -1579,6 +1580,8 @@ static int sc16is7xx_probe(struct device goto out_ports; } +mutex_init (&s->p[i].efr_lock); + ret =uart_get_rs485_mode (&s->p[i].port);if (ret) goto out_ports;
Greg Kroah-Hartman
maintainerPATCH 132/346 serial: sc16is7xx: convert from _raw_ to _noinc_ regmap functions for FIFO
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hugo Villeneuve <[email protected]>
commit dbf4ab821804df071c8b566d9813083125e6d97b upstream.
The SC16IS7XX IC supports a burst mode to access the FIFOs where the initial register address is sent ($00), followed by all the FIFO data without having to resend the register address each time. In this mode, the IC doesn't increment the register address for each R/W byte.
The regmap_raw_read() and regmap_raw_write() are functions which can perform IO over multiple registers. They are currently used to read/write from/to the FIFO, and although they operate correctly in this burst mode on the SPI bus, they would corrupt the regmap cache if it was not disabled manually. The reason is that when the R/W size is more than 1 byte, these functions assume that the register address is incremented and handle the cache accordingly.
Convert FIFO R/W functions to use the regmap _noinc_ versions in order to remove the manual cache control which was a workaround when using the _raw_ versions. FIFO registers are properly declared as volatile so cache will not be used/updated for FIFO accesses.
--- drivers/tty/serial/sc16is7xx.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-)
drivers/tty/serial/sc16is7xx.c +11 -6
@@ -382,9 +382,7 @@ static void sc16is7xx_fifo_read(struct ustruct sc16is7xx_port *s =dev_get_drvdata (port->dev);struct sc16is7xx_one *one =to_sc16is7xx_one (port, port); -regcache_cache_bypass (one->regmap, true); -regmap_raw_read (one->regmap,SC16IS7XX_RHR_REG , s->buf, rxlen); -regcache_cache_bypass (one->regmap, false); +regmap_noinc_read (one->regmap,SC16IS7XX_RHR_REG , s->buf, rxlen); }static void sc16is7xx_fifo_write (struct uart_port *port,u8 to_send)
@@ -399,9 +397,7 @@ static void sc16is7xx_fifo_write(structif (unlikely (!to_send))return ; -regcache_cache_bypass (one->regmap, true); -regmap_raw_write (one->regmap,SC16IS7XX_THR_REG , s->buf, to_send); -regcache_cache_bypass (one->regmap, false); +regmap_noinc_write (one->regmap,SC16IS7XX_THR_REG , s->buf, to_send); } static void sc16is7xx_port_update(struct uart_port *port, u8 reg,
@@ -493,6 +489,11 @@ static bool sc16is7xx_regmap_precious(streturn false; } +static bool sc16is7xx_regmap_noinc (struct device *dev,unsigned int reg) +{ +return reg ==SC16IS7XX_RHR_REG ; +} +static int sc16is7xx_set_baud (struct uart_port *port,int baud) {struct sc16is7xx_one *one =to_sc16is7xx_one (port, port);
@@ -1710,6 +1711,10 @@ static struct regmap_config regcfg = { .cache_type = REGCACHE_RBTREE, .volatile_reg = sc16is7xx_regmap_volatile, .precious_reg = sc16is7xx_regmap_precious, + .writeable_noinc_reg = sc16is7xx_regmap_noinc, + .readable_noinc_reg = sc16is7xx_regmap_noinc, + .max_raw_read = SC16IS7XX_FIFO_SIZE, + .max_raw_write = SC16IS7XX_FIFO_SIZE, .max_register = SC16IS7XX_EFCR_REG, };
Greg Kroah-Hartman
maintainerPATCH 133/346 serial: sc16is7xx: fix unconditional activation of THRI interrupt
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hugo Villeneuve <[email protected]>
commit 9915753037eba7135b209fef4f2afeca841af816 upstream.
Commit cc4c1d05eb10 ("sc16is7xx: Properly resume TX after stop") changed behavior to unconditionnaly set the THRI interrupt in sc16is7xx_tx_proc().
For example when sending a 65 bytes message, and assuming the Tx FIFO is initially empty, sc16is7xx_handle_tx() will write the first 64 bytes of the message to the FIFO and sc16is7xx_tx_proc() will then activate THRI. When the THRI IRQ is fired, the driver will write the remaining byte of the message to the FIFO, and disable THRI by calling sc16is7xx_stop_tx().
When sending a 2 bytes message, sc16is7xx_handle_tx() will write the 2 bytes of the message to the FIFO and call sc16is7xx_stop_tx(), disabling THRI. After sc16is7xx_handle_tx() exits, control returns to sc16is7xx_tx_proc() which will unconditionally set THRI. When the THRI IRQ is fired, the driver simply acknowledges the interrupt and does nothing more, since all the data has already been written to the FIFO. This results in 2 register writes and 4 register reads all for nothing and taking precious cycles from the I2C/SPI bus.
Fix this by enabling the THRI interrupt only when we fill the Tx FIFO to its maximum capacity and there are remaining bytes to send in the message.
--- drivers/tty/serial/sc16is7xx.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
drivers/tty/serial/sc16is7xx.c +2 -5
@@ -688,6 +688,8 @@ static void sc16is7xx_handle_tx(struct uif (uart_circ_empty (xmit))sc16is7xx_stop_tx (port); +else +sc16is7xx_ier_set (port,SC16IS7XX_IER_THRI_BIT );uart_port_unlock_irqrestore (port, flags); }
@@ -816,7 +818,6 @@ static void sc16is7xx_tx_proc(struct kth {struct uart_port *port = &(to_sc16is7xx_one (ws, tx_work)->port);struct sc16is7xx_one *one =to_sc16is7xx_one (port, port); -unsigned long flags;if ((port->rs485.flags &SER_RS485_ENABLED ) && (port->rs485.delay_rts_before_send >0 ))
@@ -825,10 +826,6 @@ static void sc16is7xx_tx_proc(struct kthmutex_lock (&one->efr_lock);sc16is7xx_handle_tx (port);mutex_unlock (&one->efr_lock); - -uart_port_lock_irqsave (port, &flags); -sc16is7xx_ier_set (port,SC16IS7XX_IER_THRI_BIT ); -uart_port_unlock_irqrestore (port, flags); }static void sc16is7xx_reconf_rs485 (struct uart_port *port)
Greg Kroah-Hartman
maintainerPATCH 134/346 serial: sc16is7xx: fix invalid sc16is7xx_lines bitfield in case of probe error
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hugo Villeneuve <[email protected]>
commit 8a1060ce974919f2a79807527ad82ac39336eda2 upstream.
If an error occurs during probing, the sc16is7xx_lines bitfield may be left in a state that doesn't represent the correct state of lines allocation.
For example, in a system with two SC16 devices, if an error occurs only during probing of channel (port) B of the second device, sc16is7xx_lines final state will be 00001011b instead of the expected 00000011b.
This is caused in part because of the "i--" in the for/loop located in the out_ports: error path.
Fix this by checking the return value of uart_add_one_port() and set line allocation bit only if this was successful. This allows the refactor of the obfuscated for(i--...) loop in the error path, and properly call uart_remove_one_port() only when needed, and properly unset line allocation bits.
Also use same mechanism in remove() when calling uart_remove_one_port().
--- drivers/tty/serial/sc16is7xx.c | 44 ++++++++++++++++------------------------- 1 file changed, 18 insertions(+), 26 deletions(-)
drivers/tty/serial/sc16is7xx.c +18 -26
@@ -408,19 +408,6 @@ static void sc16is7xx_port_update(structregmap_update_bits (one->regmap, reg, mask, val); } -static int sc16is7xx_alloc_line (void ) -{ -int i; - -BUILD_BUG_ON (SC16IS7XX_MAX_DEVS >BITS_PER_LONG ); - -for (i =0 ; i <SC16IS7XX_MAX_DEVS ; i++) -if (!test_and_set_bit (i, &sc16is7xx_lines)) -break ; - -return i; -} -static void sc16is7xx_power (struct uart_port *port,int on) { sc16is7xx_port_update(port, SC16IS7XX_IER_REG,
@@ -1551,6 +1538,13 @@ static int sc16is7xx_probe(struct device SC16IS7XX_IOCONTROL_SRESET_BIT);for (i =0 ; i < devtype->nr_uart; ++i) { + s->p[i].port.line =find_first_zero_bit (&sc16is7xx_lines, +SC16IS7XX_MAX_DEVS ); +if (s->p[i].port.line >=SC16IS7XX_MAX_DEVS ) { + ret = -ERANGE ; + goto out_ports; + } +/* Initialize port data */ s->p[i].port.dev = dev; s->p[i].port.irq = irq;
@@ -1570,14 +1564,8 @@ static int sc16is7xx_probe(struct device s->p[i].port.rs485_supported = sc16is7xx_rs485_supported; s->p[i].port.ops = &sc16is7xx_ops; s->p[i].old_mctrl =0 ; - s->p[i].port.line =sc16is7xx_alloc_line (); s->p[i].regmap = regmaps[i]; -if (s->p[i].port.line >=SC16IS7XX_MAX_DEVS ) { - ret = -ENOMEM ; - goto out_ports; - } -mutex_init (&s->p[i].efr_lock); ret =uart_get_rs485_mode (&s->p[i].port);
@@ -1595,8 +1583,13 @@ static int sc16is7xx_probe(struct devicekthread_init_work (&s->p[i].tx_work, sc16is7xx_tx_proc);kthread_init_work (&s->p[i].reg_work, sc16is7xx_reg_proc);kthread_init_delayed_work (&s->p[i].ms_work, sc16is7xx_ms_proc); +/* Register port */ -uart_add_one_port (&sc16is7xx_uart, &s->p[i].port); + ret =uart_add_one_port (&sc16is7xx_uart, &s->p[i].port); +if (ret) + goto out_ports; + +set_bit (s->p[i].port.line, &sc16is7xx_lines);/* Enable EFR */ sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_LCR_REG,
@@ -1654,10 +1647,9 @@ static int sc16is7xx_probe(struct device#endif out_ports: -for (i--; i >=0 ; i--) { -uart_remove_one_port (&sc16is7xx_uart, &s->p[i].port); -clear_bit (s->p[i].port.line, &sc16is7xx_lines); - } +for (i =0 ; i < devtype->nr_uart; i++) +if (test_and_clear_bit (s->p[i].port.line, &sc16is7xx_lines)) +uart_remove_one_port (&sc16is7xx_uart, &s->p[i].port);kthread_stop (s->kworker_task);
@@ -1679,8 +1671,8 @@ static void sc16is7xx_remove(struct devifor (i =0 ; i < s->devtype->nr_uart; i++) {kthread_cancel_delayed_work_sync (&s->p[i].ms_work); -uart_remove_one_port (&sc16is7xx_uart, &s->p[i].port); -clear_bit (s->p[i].port.line, &sc16is7xx_lines); +if (test_and_clear_bit (s->p[i].port.line, &sc16is7xx_lines)) +uart_remove_one_port (&sc16is7xx_uart, &s->p[i].port);sc16is7xx_power (&s->p[i].port,0 ); }
Greg Kroah-Hartman
maintainerPATCH 135/346 serial: sc16is7xx: remove obsolete loop in sc16is7xx_port_irq()
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hugo Villeneuve <[email protected]>
commit ed647256e8f226241ecff7baaecdb8632ffc7ec1 upstream.
Commit 834449872105 ("sc16is7xx: Fix for multi-channel stall") changed sc16is7xx_port_irq() from looping multiple times when there was still interrupts to serve. It simply changed the do {} while(1) loop to a do {} while(0) loop, which makes the loop itself now obsolete.
Clean the code by removing this obsolete do {} while(0) loop.
--- drivers/tty/serial/sc16is7xx.c | 89 +++++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 46 deletions(-)
drivers/tty/serial/sc16is7xx.c +43 -46
@@ -725,58 +725,55 @@ static void sc16is7xx_update_mlines(strustatic bool sc16is7xx_port_irq (struct sc16is7xx_port *s,int portno) {bool rc = true; +unsigned int iir, rxlen;struct uart_port *port = &s->p[portno].port;struct sc16is7xx_one *one =to_sc16is7xx_one (port, port);mutex_lock (&one->efr_lock); -do { -unsigned int iir, rxlen; - - iir =sc16is7xx_port_read (port,SC16IS7XX_IIR_REG ); -if (iir &SC16IS7XX_IIR_NO_INT_BIT ) { - rc = false; - goto out_port_irq; - } - - iir &=SC16IS7XX_IIR_ID_MASK ; - -switch (iir) { -case SC16IS7XX_IIR_RDI_SRC : -case SC16IS7XX_IIR_RLSE_SRC : -case SC16IS7XX_IIR_RTOI_SRC : -case SC16IS7XX_IIR_XOFFI_SRC : - rxlen =sc16is7xx_port_read (port,SC16IS7XX_RXLVL_REG ); - -/* -* There is a silicon bug that makes the chip report a -* time-out interrupt but no data in the FIFO. This is -* described in errata section 18.1.4. -* -* When this happens, read one byte from the FIFO to -* clear the interrupt. -*/ -if (iir ==SC16IS7XX_IIR_RTOI_SRC && !rxlen) - rxlen =1 ; - -if (rxlen) -sc16is7xx_handle_rx (port, rxlen, iir); -break ; + iir =sc16is7xx_port_read (port,SC16IS7XX_IIR_REG ); +if (iir &SC16IS7XX_IIR_NO_INT_BIT ) { + rc = false; + goto out_port_irq; + } + + iir &=SC16IS7XX_IIR_ID_MASK ; + +switch (iir) { +case SC16IS7XX_IIR_RDI_SRC : +case SC16IS7XX_IIR_RLSE_SRC : +case SC16IS7XX_IIR_RTOI_SRC : +case SC16IS7XX_IIR_XOFFI_SRC : + rxlen =sc16is7xx_port_read (port,SC16IS7XX_RXLVL_REG ); + +/* +* There is a silicon bug that makes the chip report a +* time-out interrupt but no data in the FIFO. This is +* described in errata section 18.1.4. +* +* When this happens, read one byte from the FIFO to +* clear the interrupt. +*/ +if (iir ==SC16IS7XX_IIR_RTOI_SRC && !rxlen) + rxlen =1 ; + +if (rxlen) +sc16is7xx_handle_rx (port, rxlen, iir); +break ;/* CTSRTS interrupt comes only when CTS goes inactive */ -case SC16IS7XX_IIR_CTSRTS_SRC : -case SC16IS7XX_IIR_MSI_SRC : -sc16is7xx_update_mlines (one); -break ; -case SC16IS7XX_IIR_THRI_SRC : -sc16is7xx_handle_tx (port); -break ; -default : -dev_err_ratelimited (port->dev, -"ttySC%i: Unexpected interrupt: %x" , - port->line, iir); -break ; - } - }while (0 ); +case SC16IS7XX_IIR_CTSRTS_SRC : +case SC16IS7XX_IIR_MSI_SRC : +sc16is7xx_update_mlines (one); +break ; +case SC16IS7XX_IIR_THRI_SRC : +sc16is7xx_handle_tx (port); +break ; +default : +dev_err_ratelimited (port->dev, +"ttySC%i: Unexpected interrupt: %x" , + port->line, iir); +break ; + } out_port_irq:mutex_unlock (&one->efr_lock);
Greg Kroah-Hartman
maintainerPATCH 136/346 serial: sc16is7xx: improve do/while loop in sc16is7xx_irq()
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hugo Villeneuve <[email protected]>
commit d5078509c8b06c5c472a60232815e41af81c6446 upstream.
Simplify and improve readability by replacing while(1) loop with do {} while, and by using the keep_polling variable as the exit condition, making it more explicit.
--- drivers/tty/serial/sc16is7xx.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
drivers/tty/serial/sc16is7xx.c +6 -5
@@ -783,17 +783,18 @@ out_port_irq:static irqreturn_t sc16is7xx_irq (int irq,void *dev_id) { +bool keep_polling; +struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id; -while (1 ) { -bool keep_polling = false; +do {int i; + keep_polling = false; +for (i =0 ; i < s->devtype->nr_uart; ++i) keep_polling |=sc16is7xx_port_irq (s, i); -if (!keep_polling) -break ; - } + }while (keep_polling);return IRQ_HANDLED ; }
Greg Kroah-Hartman
maintainerPATCH 137/346 mm: page_alloc: unreserve highatomic page blocks before oom
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Charan Teja Kalla <[email protected]>
commit ac3f3b0a55518056bc80ed32a41931c99e1f7d81 upstream.
__alloc_pages_direct_reclaim() is called from slowpath allocation where high atomic reserves can be unreserved after there is a progress in reclaim and yet no suitable page is found. Later should_reclaim_retry() gets called from slow path allocation to decide if the reclaim needs to be retried before OOM kill path is taken.
should_reclaim_retry() checks the available(reclaimable + free pages) memory against the min wmark levels of a zone and returns:
a) true, if it is above the min wmark so that slow path allocation will do the reclaim retries.
b) false, thus slowpath allocation takes oom kill path.
should_reclaim_retry() can also unreserves the high atomic reserves **but only after all the reclaim retries are exhausted.**
In a case where there are almost none reclaimable memory and free pages contains mostly the high atomic reserves but allocation context can't use these high atomic reserves, makes the available memory below min wmark levels hence false is returned from should_reclaim_retry() leading the allocation request to take OOM kill path. This can turn into a early oom kill if high atomic reserves are holding lot of free memory and unreserving of them is not attempted.
(early)OOM is encountered on a VM with the below state:
[ 295.998653] Normal free:7728kB boost:0kB min:804kB low:1004kB
high:1204kB reserved_highatomic:8192KB active_anon:4kB inactive_anon:0kB active_file:24kB inactive_file:24kB unevictable:1220kB writepending:0kB present:70732kB managed:49224kB mlocked:0kB bounce:0kB free_pcp:688kB local_pcp:492kB free_cma:0kB
[ 295.998656] lowmem_reserve[]: 0 32 [ 295.998659] Normal: 508*4kB (UMEH) 241*8kB (UMEH) 143*16kB (UMEH)
33*32kB (UH) 7*64kB (UH) 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 7752kB
Per above log, the free memory of ~7MB exist in the high atomic reserves is not freed up before falling back to oom kill path.
Fix it by trying to unreserve the high atomic reserves in should_reclaim_retry() before __alloc_pages_direct_reclaim() can fallback to oom kill path.
--- mm/page_alloc.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
mm/page_alloc.c +8 -8
@@ -3951,14 +3951,9 @@ should_reclaim_retry(gfp_t gfp_mask, unselse (*no_progress_loops)++; -/* -* Make sure we converge to OOM if we cannot make any progress -* several times in the row. -*/ -if (*no_progress_loops >MAX_RECLAIM_RETRIES ) { -/* Before OOM, exhaust highatomic_reserve */ -return unreserve_highatomic_pageblock (ac, true); - } +if (*no_progress_loops >MAX_RECLAIM_RETRIES ) + goto out; +/* * Keep reclaiming pages while there is a chance this will lead
@@ -4001,6 +3996,11 @@ should_reclaim_retry(gfp_t gfp_mask, unsschedule_timeout_uninterruptible (1 ); elsecond_resched (); +out: +/* Before OOM, exhaust highatomic_reserve */ +if (!ret) +return unreserve_highatomic_pageblock (ac, true); +return ret; }
Greg Kroah-Hartman
maintainerPATCH 138/346 ksmbd: set v2 lease version on lease upgrade
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit bb05367a66a9990d2c561282f5620bb1dbe40c28 ]
If file opened with v2 lease is upgraded with v1 lease, smb server should response v2 lease create context to client.
This patch fix smb2.lease.v2_epoch2 test failure.
This test case assumes the following scenario:
1. smb2 create with v2 lease(R, LEASE1 key)
2. smb server return smb2 create response with v2 lease context(R,
LEASE1 key, epoch + 1)
3. smb2 create with v1 lease(RH, LEASE1 key)
4. smb server return smb2 create response with v2 lease context(RH,
LEASE1 key, epoch + 2)
i.e. If same client(same lease key) try to open a file that is being opened with v2 lease with v1 lease, smb server should return v2 lease.
--- fs/smb/server/oplock.c | 1 + 1 file changed, 1 insertion(+)
fs/smb/server/oplock.c +1 -0
@@ -1036,6 +1036,7 @@ static void copy_lease(struct oplock_inf lease2->duration = lease1->duration; lease2->flags = lease1->flags; lease2->epoch = lease1->epoch++; + lease2->version = lease1->version; }static int add_lease_global_list (struct oplock_info *opinfo)
Greg Kroah-Hartman
maintainerPATCH 139/346 wifi: ath11k: rely on mac80211 debugfs handling for vif
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Berg <[email protected]>
commit 556857aa1d0855aba02b1c63bc52b91ec63fc2cc upstream.
mac80211 started to delete debugfs entries in certain cases, causing a ath11k to crash when it tried to delete the entries later. Fix this by relying on mac80211 to delete the entries when appropriate and adding them from the vif_add_debugfs handler.
--- drivers/net/wireless/ath/ath11k/core.h | 4 ---- drivers/net/wireless/ath/ath11k/debugfs.c | 25 ++++++++++--------------- drivers/net/wireless/ath/ath11k/debugfs.h | 12 ++---------- drivers/net/wireless/ath/ath11k/mac.c | 12 +----------- 4 files changed, 13 insertions(+), 40 deletions(-)
drivers/net/wireless/ath/ath11k/core.h +0 -4
@@ -368,10 +368,6 @@ struct ath11k_vif {struct ieee80211_chanctx_conf chanctx;struct ath11k_arp_ns_offload arp_ns_offload;struct ath11k_rekey_data rekey_data; - -#ifdef CONFIG_ATH11K_DEBUGFS -struct dentry *debugfs_twt; -#endif /* CONFIG_ATH11K_DEBUGFS */ };struct ath11k_vif_iter {
drivers/net/wireless/ath/ath11k/debugfs.c +10 -15
@@ -1893,35 +1893,30 @@ static const struct file_operations ath1 .open = simple_open }; -void ath11k_debugfs_add_interface (struct ath11k_vif *arvif) +void ath11k_debugfs_op_vif_add (struct ieee80211_hw *hw, +struct ieee80211_vif *vif) { +struct ath11k_vif *arvif =ath11k_vif_to_arvif (vif);struct ath11k_base *ab = arvif->ar->ab; +struct dentry *debugfs_twt;if (arvif->vif->type !=NL80211_IFTYPE_AP && !(arvif->vif->type ==NL80211_IFTYPE_STATION &&test_bit (WMI_TLV_SERVICE_STA_TWT , ab->wmi_ab.svc_map)))return ; - arvif->debugfs_twt =debugfs_create_dir ("twt" , - arvif->vif->debugfs_dir); -debugfs_create_file ("add_dialog" ,0200 , arvif->debugfs_twt, + debugfs_twt =debugfs_create_dir ("twt" , + arvif->vif->debugfs_dir); +debugfs_create_file ("add_dialog" ,0200 , debugfs_twt, arvif, &ath11k_fops_twt_add_dialog); -debugfs_create_file ("del_dialog" ,0200 , arvif->debugfs_twt, +debugfs_create_file ("del_dialog" ,0200 , debugfs_twt, arvif, &ath11k_fops_twt_del_dialog); -debugfs_create_file ("pause_dialog" ,0200 , arvif->debugfs_twt, +debugfs_create_file ("pause_dialog" ,0200 , debugfs_twt, arvif, &ath11k_fops_twt_pause_dialog); -debugfs_create_file ("resume_dialog" ,0200 , arvif->debugfs_twt, +debugfs_create_file ("resume_dialog" ,0200 , debugfs_twt, arvif, &ath11k_fops_twt_resume_dialog); } -void ath11k_debugfs_remove_interface (struct ath11k_vif *arvif) -{ -if (!arvif->debugfs_twt) -return ; - -debugfs_remove_recursive (arvif->debugfs_twt); - arvif->debugfs_twt =NULL ; -}
drivers/net/wireless/ath/ath11k/debugfs.h +2 -10
@@ -306,8 +306,8 @@ static inline int ath11k_debugfs_rx_filtreturn ar->debug.rx_filter; } -void ath11k_debugfs_add_interface (struct ath11k_vif *arvif); -void ath11k_debugfs_remove_interface (struct ath11k_vif *arvif); +void ath11k_debugfs_op_vif_add (struct ieee80211_hw *hw, +struct ieee80211_vif *vif); void ath11k_debugfs_add_dbring_entry(struct ath11k *ar, enum wmi_direct_buffer_module id, enum ath11k_dbg_dbr_event event,
@@ -386,14 +386,6 @@ static inline int ath11k_debugfs_get_fw_return 0 ; } -static inline void ath11k_debugfs_add_interface (struct ath11k_vif *arvif) -{ -} - -static inline void ath11k_debugfs_remove_interface (struct ath11k_vif *arvif) -{ -} - static inline void ath11k_debugfs_add_dbring_entry(struct ath11k *ar, enum wmi_direct_buffer_module id,
drivers/net/wireless/ath/ath11k/mac.c +1 -11
@@ -6750,13 +6750,6 @@ static int ath11k_mac_op_add_interface(s goto err; } -/* In the case of hardware recovery, debugfs files are -* not deleted since ieee80211_ops.remove_interface() is -* not invoked. In such cases, try to delete the files. -* These will be re-created later. -*/ -ath11k_debugfs_remove_interface (arvif); -memset (arvif,0 ,sizeof (*arvif)); arvif->ar = ar;
@@ -6933,8 +6926,6 @@ static int ath11k_mac_op_add_interface(sath11k_dp_vdev_tx_attach (ar, arvif); -ath11k_debugfs_add_interface (arvif); -if (vif->type !=NL80211_IFTYPE_MONITOR &&test_bit (ATH11K_FLAG_MONITOR_CONF_ENABLED , &ar->monitor_flags)) { ret =ath11k_mac_monitor_vdev_create (ar);
@@ -7050,8 +7041,6 @@ err_vdev_del:/* Recalc txpower for remaining vdev */ ath11k_mac_txpower_recalc (ar); -ath11k_debugfs_remove_interface (arvif); -/* TODO: recal traffic pause state based on the available vdevs */ mutex_unlock (&ar->conf_mutex);
@@ -9149,6 +9138,7 @@ static const struct ieee80211_ops ath11k#endif #ifdef CONFIG_ATH11K_DEBUGFS + .vif_add_debugfs = ath11k_debugfs_op_vif_add, .sta_add_debugfs = ath11k_debugfs_sta_op_add,#endif
Greg Kroah-Hartman
maintainerPATCH 140/346 Revert "drm/amd: Enable PCIe PME from D3"
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jonathan Gray <[email protected]>
This reverts commit 05f7a3475af0faa8bf77f8637c4a40349db4f78f.
duplicated a change made in 6.76967741d26c87300a51b5e50d4acd104bc1a9759
--- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 2 -- 1 file changed, 2 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +0 -2
@@ -2265,8 +2265,6 @@ retry_init:pci_wake_from_d3 (pdev, TRUE); -pci_wake_from_d3 (pdev, TRUE); -/* * For runpm implemented via BACO, PMFW will handle the * timing for BACO in and out:
Greg Kroah-Hartman
maintainerPATCH 141/346 ksmbd: fix potential circular locking issue in smb2_set_ea()
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit 6fc0a265e1b932e5e97a038f99e29400a93baad0 ]
smb2_set_ea() can be called in parent inode lock range. So add get_write argument to smb2_set_ea() not to call nested mnt_want_write().
--- fs/smb/server/smb2pdu.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
fs/smb/server/smb2pdu.c +4 -3
@@ -2323,11 +2323,12 @@ out:* @eabuf: set info command buffer * @buf_len: set info command buffer length * @path: dentry path for get ea +* @get_write: get write access to a mount * * Return: 0 on success, otherwise error */ static int smb2_set_ea (struct smb2_ea_info *eabuf,unsigned int buf_len, -const struct path *path) +const struct path *path,bool get_write) {struct mnt_idmap *idmap =mnt_idmap (path->mnt);char *attr_name =NULL , *value;
@@ -3015,7 +3016,7 @@ int smb2_open(struct ksmbd_work *work) rc =smb2_set_ea (&ea_buf->ea,le32_to_cpu (ea_buf->ccontext.DataLength), - &path); + &path, false);if (rc == -EOPNOTSUPP ) rc =0 ;else if (rc)
@@ -5992,7 +5993,7 @@ static int smb2_set_info_file(struct ksmreturn -EINVAL ;return smb2_set_ea ((struct smb2_ea_info *)req->Buffer, - buf_len, &fp->filp->f_path); + buf_len, &fp->filp->f_path, true); }case FILE_POSITION_INFORMATION : {
Greg Kroah-Hartman
maintainerPATCH 142/346 ksmbd: dont increment epoch if current state and request state are same
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit b6e9a44e99603fe10e1d78901fdd97681a539612 ]
If existing lease state and request state are same, don't increment epoch in create context.
--- fs/smb/server/oplock.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
fs/smb/server/oplock.c +6 -3
@@ -105,7 +105,7 @@ static int alloc_lease(struct oplock_inf lease->is_dir = lctx->is_dir;memcpy (lease->parent_lease_key, lctx->parent_lease_key,SMB2_LEASE_KEY_SIZE ); lease->version = lctx->version; - lease->epoch =le16_to_cpu (lctx->epoch); + lease->epoch =le16_to_cpu (lctx->epoch) +1 ;INIT_LIST_HEAD (&opinfo->lease_entry); opinfo->o_lease = lease;
@@ -541,6 +541,9 @@ static struct oplock_info *same_client_hcontinue ; } +if (lctx->req_state != lease->state) + lease->epoch++; +/* upgrading lease */ if ((atomic_read (&ci->op_count) +atomic_read (&ci->sop_count)) ==1 ) {
@@ -1035,7 +1038,7 @@ static void copy_lease(struct oplock_inf SMB2_LEASE_KEY_SIZE); lease2->duration = lease1->duration; lease2->flags = lease1->flags; - lease2->epoch = lease1->epoch++; + lease2->epoch = lease1->epoch; lease2->version = lease1->version; }
@@ -1454,7 +1457,7 @@ void create_lease_buf(u8 *rbuf, struct lmemcpy (buf->lcontext.LeaseKey, lease->lease_key,SMB2_LEASE_KEY_SIZE ); buf->lcontext.LeaseFlags = lease->flags; - buf->lcontext.Epoch =cpu_to_le16 (++lease->epoch); + buf->lcontext.Epoch =cpu_to_le16 (lease->epoch); buf->lcontext.LeaseState = lease->state;memcpy (buf->lcontext.ParentLeaseKey, lease->parent_lease_key,SMB2_LEASE_KEY_SIZE );
Greg Kroah-Hartman
maintainerPATCH 143/346 ksmbd: send lease break notification on FILE_RENAME_INFORMATION
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit 3fc74c65b367476874da5fe6f633398674b78e5a ]
Send lease break notification on FILE_RENAME_INFORMATION request. This patch fix smb2.lease.v2_epoch2 test failure.
--- fs/smb/server/oplock.c | 12 +++++++----- fs/smb/server/smb2pdu.c | 1 + 2 files changed, 8 insertions(+), 5 deletions(-)
fs/smb/server/oplock.c +7 -5
@@ -541,14 +541,12 @@ static struct oplock_info *same_client_hcontinue ; } -if (lctx->req_state != lease->state) - lease->epoch++; -/* upgrading lease */ if ((atomic_read (&ci->op_count) +atomic_read (&ci->sop_count)) ==1 ) {if (lease->state !=SMB2_LEASE_NONE_LE && lease->state == (lctx->req_state & lease->state)) { + lease->epoch++; lease->state |= lctx->req_state;if (lctx->req_state &SMB2_LEASE_WRITE_CACHING_LE )
@@ -559,13 +557,17 @@ static struct oplock_info *same_client_h atomic_read(&ci->sop_count)) > 1) {if (lctx->req_state == (SMB2_LEASE_READ_CACHING_LE | -SMB2_LEASE_HANDLE_CACHING_LE )) +SMB2_LEASE_HANDLE_CACHING_LE )) { + lease->epoch++; lease->state = lctx->req_state; + } }if (lctx->req_state && lease->state == -SMB2_LEASE_NONE_LE ) +SMB2_LEASE_NONE_LE ) { + lease->epoch++;lease_none_upgrade (opinfo, lctx->req_state); + } }read_lock (&ci->m_lock); }
fs/smb/server/smb2pdu.c +1 -0
@@ -5581,6 +5581,7 @@ static int smb2_rename(struct ksmbd_workif (!file_info->ReplaceIfExists) flags =RENAME_NOREPLACE ; +smb_break_all_levII_oplock (work, fp,0 ); rc =ksmbd_vfs_rename (work, &fp->filp->f_path, new_name, flags); out:kfree (new_name);
Greg Kroah-Hartman
maintainerPATCH 144/346 ksmbd: Add missing set_freezable() for freezable kthread
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
From: Kevin Hao <[email protected]>
[ Upstream commit 8fb7b723924cc9306bc161f45496497aec733904 ]
The kernel thread function ksmbd_conn_handler_loop() invokes the try_to_freeze() in its loop. But all the kernel threads are non-freezable by default. So if we want to make a kernel thread to be freezable, we have to invoke set_freezable() explicitly.
--- fs/smb/server/connection.c | 1 + 1 file changed, 1 insertion(+)
fs/smb/server/connection.c +1 -0
@@ -284,6 +284,7 @@ int ksmbd_conn_handler_loop(void *p) goto out; conn->last_active = jiffies; +set_freezable ();while (ksmbd_conn_alive (conn)) {if (try_to_freeze ())continue ;
Greg Kroah-Hartman
maintainerPATCH 145/346 SUNRPC: use request size to initialize bio_vec in svc_udp_sendto()
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lucas Stach <[email protected]>
[ Upstream commit 1d9cabe2817edd215779dc9c2fe5e7ab9aac0704 ]
Use the proper size when setting up the bio_vec, as otherwise only zero-length UDP packets will be sent.
--- net/sunrpc/svcsock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/sunrpc/svcsock.c +2 -2
@@ -717,12 +717,12 @@ static int svc_udp_sendto(struct svc_rqst *rqstp) ARRAY_SIZE(rqstp->rq_bvec), xdr);iov_iter_bvec (&msg.msg_iter,ITER_SOURCE , rqstp->rq_bvec, - count,0 ); + count, rqstp->rq_res.len); err =sock_sendmsg (svsk->sk_sock, &msg);if (err == -ECONNREFUSED ) {/* ICMP error on earlier request. */ iov_iter_bvec (&msg.msg_iter,ITER_SOURCE , rqstp->rq_bvec, - count,0 ); + count, rqstp->rq_res.len); err =sock_sendmsg (svsk->sk_sock, &msg); }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 146/346 wifi: mac80211: fix potential sta-link leak
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johannes Berg <[email protected]>
[ Upstream commit b01a74b3ca6fd51b62c67733ba7c3280fa6c5d26 ]
When a station is allocated, links are added but not set to valid yet (e.g. during connection to an AP MLD), we might remove the station without ever marking links valid, and leak them. Fix that.
--- net/mac80211/sta_info.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
net/mac80211/sta_info.c +4 -1
@@ -404,7 +404,10 @@ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)int i;for (i =0 ; i <ARRAY_SIZE (sta->link); i++) { -if (!(sta->sta.valid_links &BIT (i))) +struct link_sta_info *link_sta; + + link_sta =rcu_access_pointer (sta->link[i]); +if (!link_sta)continue ;sta_remove_link (sta, i, false);
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 147/346 btrfs: scrub: avoid use-after-free when chunk length is not 64K aligned
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo <[email protected]>
[ Upstream commit f546c4282673497a06ecb6190b50ae7f6c85b02f ]
[BUG]
There is a bug report that, on a ext4-converted btrfs, scrub leads to various problems, including:
- "unable to find chunk map" errors
BTRFS info (device vdb): scrub: started on devid 1
BTRFS critical (device vdb): unable to find chunk map for logical 2214744064 length 4096 BTRFS critical (device vdb): unable to find chunk map for logical 2214744064 length 45056
This would lead to unrepariable errors.
- Use-after-free KASAN reports:
==================================================================
BUG: KASAN: slab-use-after-free in __blk_rq_map_sg+0x18f/0x7c0 Read of size 8 at addr ffff8881013c9040 by task btrfs/909 CPU: 0 PID: 909 Comm: btrfs Not tainted 6.7.0-x64v3-dbg #11 c50636e9419a8354555555245df535e380563b2b Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 2023.11-2 12/24/2023 Call Trace: <TASK> dump_stack_lvl+0x43/0x60 print_report+0xcf/0x640 kasan_report+0xa6/0xd0 __blk_rq_map_sg+0x18f/0x7c0 virtblk_prep_rq.isra.0+0x215/0x6a0 [virtio_blk 19a65eeee9ae6fcf02edfad39bb9ddee07dcdaff] virtio_queue_rqs+0xc4/0x310 [virtio_blk 19a65eeee9ae6fcf02edfad39bb9ddee07dcdaff] blk_mq_flush_plug_list.part.0+0x780/0x860 __blk_flush_plug+0x1ba/0x220 blk_finish_plug+0x3b/0x60 submit_initial_group_read+0x10a/0x290 [btrfs e57987a360bed82fe8756dcd3e0de5406ccfe965] flush_scrub_stripes+0x38e/0x430 [btrfs e57987a360bed82fe8756dcd3e0de5406ccfe965] scrub_stripe+0x82a/0xae0 [btrfs e57987a360bed82fe8756dcd3e0de5406ccfe965] scrub_chunk+0x178/0x200 [btrfs e57987a360bed82fe8756dcd3e0de5406ccfe965] scrub_enumerate_chunks+0x4bc/0xa30 [btrfs e57987a360bed82fe8756dcd3e0de5406ccfe965] btrfs_scrub_dev+0x398/0x810 [btrfs e57987a360bed82fe8756dcd3e0de5406ccfe965] btrfs_ioctl+0x4b9/0x3020 [btrfs e57987a360bed82fe8756dcd3e0de5406ccfe965] __x64_sys_ioctl+0xbd/0x100 do_syscall_64+0x5d/0xe0 entry_SYSCALL_64_after_hwframe+0x63/0x6b RIP: 0033:0x7f47e5e0952b
- Crash, mostly due to above use-after-free
[CAUSE]
The converted fs has the following data chunk layout:
item 2 key (FIRST_CHUNK_TREE CHUNK_ITEM 2214658048) itemoff 16025 itemsize 80
length 86016 owner 2 stripe_len 65536 type DATA|single
For above logical bytenr 2214744064, it's at the chunk end (2214658048 + 86016 = 2214744064).
This means btrfs_submit_bio() would split the bio, and trigger endio function for both of the two halves.
However scrub_submit_initial_read() would only expect the endio function to be called once, not any more.
This means the first endio function would already free the bbio::bio, leaving the bvec freed, thus the 2nd endio call would lead to use-after-free.
[FIX]
- Make sure scrub_read_endio() only updates bits in its range Since we may read less than 64K at the end of the chunk, we should not touch the bits beyond chunk boundary.
- Make sure scrub_submit_initial_read() only to read the chunk range This is done by calculating the real number of sectors we need to read, and add sector-by-sector to the bio.
Thankfully the scrub read repair path won't need extra fixes:
- scrub_stripe_submit_repair_read()
With above fixes, we won't update error bit for range beyond chunk, thus scrub_stripe_submit_repair_read() should never submit any read beyond the chunk.
--- fs/btrfs/scrub.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-)
fs/btrfs/scrub.c +22 -7
@@ -1099,12 +1099,22 @@ static void scrub_stripe_read_repair_worker(struct work_struct *work)static void scrub_read_endio (struct btrfs_bio *bbio) {struct scrub_stripe *stripe = bbio->private; +struct bio_vec *bvec; +int sector_nr =calc_sector_number (stripe,bio_first_bvec_all (&bbio->bio)); +int num_sectors; +u32 bio_size =0 ; +int i; + +ASSERT (sector_nr < stripe->nr_sectors); +bio_for_each_bvec_all (bvec, &bbio->bio, i) + bio_size += bvec->bv_len; + num_sectors = bio_size >> stripe->bg->fs_info->sectorsize_bits;if (bbio->bio.bi_status) { -bitmap_set (&stripe->io_error_bitmap,0 , stripe->nr_sectors); -bitmap_set (&stripe->error_bitmap,0 , stripe->nr_sectors); +bitmap_set (&stripe->io_error_bitmap, sector_nr, num_sectors); +bitmap_set (&stripe->error_bitmap, sector_nr, num_sectors); }else { -bitmap_clear (&stripe->io_error_bitmap,0 , stripe->nr_sectors); +bitmap_clear (&stripe->io_error_bitmap, sector_nr, num_sectors); }bio_put (&bbio->bio);if (atomic_dec_and_test (&stripe->pending_io)) {
@@ -1705,6 +1715,9 @@ static void scrub_submit_initial_read(struct scrub_ctx *sctx, {struct btrfs_fs_info *fs_info = sctx->fs_info;struct btrfs_bio *bbio; +unsigned int nr_sectors =min (BTRFS_STRIPE_LEN , stripe->bg->start + + stripe->bg->length - stripe->logical) >> + fs_info->sectorsize_bits;int mirror = stripe->mirror_num;ASSERT (stripe->bg);
@@ -1719,14 +1732,16 @@ static void scrub_submit_initial_read(struct scrub_ctx *sctx, bbio =btrfs_bio_alloc (SCRUB_STRIPE_PAGES ,REQ_OP_READ , fs_info, scrub_read_endio, stripe); -/* Read the whole stripe. */ bbio->bio.bi_iter.bi_sector = stripe->logical >>SECTOR_SHIFT ; -for (int i =0 ; i <BTRFS_STRIPE_LEN >>PAGE_SHIFT ; i++) { +/* Read the whole range inside the chunk boundary. */ +for (unsigned int cur =0 ; cur < nr_sectors; cur++) { +struct page *page =scrub_stripe_get_page (stripe, cur); +unsigned int pgoff =scrub_stripe_get_page_offset (stripe, cur);int ret; - ret =bio_add_page (&bbio->bio, stripe->pages[i],PAGE_SIZE ,0 ); + ret =bio_add_page (&bbio->bio, page, fs_info->sectorsize, pgoff);/* We should have allocated enough bio vectors. */ -ASSERT (ret ==PAGE_SIZE ); +ASSERT (ret == fs_info->sectorsize); }atomic_inc (&stripe->pending_io);
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 148/346 net/smc: fix illegal rmb_desc access in SMC-D connection dump
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wen Gu <[email protected]>
[ Upstream commit dbc153fd3c142909e564bb256da087e13fbf239c ]
A crash was found when dumping SMC-D connections. It can be reproduced by following steps:
- run nginx/wrk test:
smc_run nginx
smc_run wrk -t 16 -c 1000 -d <duration> -H 'Connection: Close' <URL>
- continuously dump SMC-D connections in parallel:
watch -n 1 'smcss -D'
BUG: kernel NULL pointer dereference, address: 0000000000000030 CPU: 2 PID: 7204 Comm: smcss Kdump: loaded Tainted: G E 6.7.0+ #55 RIP: 0010:__smc_diag_dump.constprop.0+0x5e5/0x620 [smc_diag] Call Trace: <TASK> ? __die+0x24/0x70 ? page_fault_oops+0x66/0x150 ? exc_page_fault+0x69/0x140 ? asm_exc_page_fault+0x26/0x30 ? __smc_diag_dump.constprop.0+0x5e5/0x620 [smc_diag] ? __kmalloc_node_track_caller+0x35d/0x430 ? __alloc_skb+0x77/0x170 smc_diag_dump_proto+0xd0/0xf0 [smc_diag] smc_diag_dump+0x26/0x60 [smc_diag] netlink_dump+0x19f/0x320 __netlink_dump_start+0x1dc/0x300 smc_diag_handler_dump+0x6a/0x80 [smc_diag] ? __pfx_smc_diag_dump+0x10/0x10 [smc_diag] sock_diag_rcv_msg+0x121/0x140 ? __pfx_sock_diag_rcv_msg+0x10/0x10 netlink_rcv_skb+0x5a/0x110 sock_diag_rcv+0x28/0x40 netlink_unicast+0x22a/0x330 netlink_sendmsg+0x1f8/0x420 __sock_sendmsg+0xb0/0xc0 ____sys_sendmsg+0x24e/0x300 ? copy_msghdr_from_user+0x62/0x80 ___sys_sendmsg+0x7c/0xd0 ? __do_fault+0x34/0x160 ? do_read_fault+0x5f/0x100 ? do_fault+0xb0/0x110 ? __handle_mm_fault+0x2b0/0x6c0 __sys_sendmsg+0x4d/0x80 do_syscall_64+0x69/0x180 entry_SYSCALL_64_after_hwframe+0x6e/0x76
It is possible that the connection is in process of being established when we dump it. Assumed that the connection has been registered in a link group by smc_conn_create() but the rmb_desc has not yet been initialized by smc_buf_create(), thus causing the illegal access to conn->rmb_desc. So fix it by checking before dump.
--- net/smc/smc_diag.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/smc/smc_diag.c +1 -1
@@ -163,7 +163,7 @@ static int __smc_diag_dump(struct sock *sk, struct sk_buff *skb, }if (smc_conn_lgr_valid (&smc->conn) && smc->conn.lgr->is_smcd && (req->diag_ext & (1 << (SMC_DIAG_DMBINFO -1 ))) && - !list_empty (&smc->conn.lgr->list)) { + !list_empty (&smc->conn.lgr->list) && smc->conn.rmb_desc) {struct smc_connection *conn = &smc->conn;struct smcd_diag_dmbinfo dinfo;struct smcd_dev *smcd = conn->lgr->smcd;
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 149/346 selftests: bonding: Increase timeout to 1200s
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benjamin Poirier <[email protected]>
[ Upstream commit b01f15a7571b7aa222458bc9bf26ab59bd84e384 ]
When tests are run by runner.sh, bond_options.sh gets killed before it can complete:
make -C tools/testing/selftests run_tests TARGETS="drivers/net/bonding"
[...]
# timeout set to 120
# selftests: drivers/net/bonding: bond_options.sh
# TEST: prio (active-backup miimon primary_reselect 0) [ OK ]
# TEST: prio (active-backup miimon primary_reselect 1) [ OK ]
# TEST: prio (active-backup miimon primary_reselect 2) [ OK ]
# TEST: prio (active-backup arp_ip_target primary_reselect 0) [ OK ]
# TEST: prio (active-backup arp_ip_target primary_reselect 1) [ OK ]
# TEST: prio (active-backup arp_ip_target primary_reselect 2) [ OK ]
#
not ok 7 selftests: drivers/net/bonding: bond_options.sh # TIMEOUT 120 seconds
This test includes many sleep statements, at least some of which are related to timers in the operation of the bonding driver itself. Increase the test timeout to allow the test to complete.
I ran the test in slightly different VMs (including one without HW virtualization support) and got runtimes of 13m39.760s, 13m31.238s, and 13m2.956s. Use a ~1.5x "safety factor" and set the timeout to 1200s.
--- tools/testing/selftests/drivers/net/bonding/settings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/testing/selftests/drivers/net/bonding/settings +1 -1
@@ -1 +1 @@ -timeout=120 +timeout=1200
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 150/346 tcp: make sure init the accept_queues spinlocks once
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhengchao Shao <[email protected]>
[ Upstream commit 198bc90e0e734e5f98c3d2833e8390cac3df61b2 ]
When I run syz's reproduction C program locally, it causes the following issue:
pvqspinlock: lock 0xffff9d181cd5c660 has corrupted value 0x0!
WARNING: CPU: 19 PID: 21160 at __pv_queued_spin_unlock_slowpath (kernel/locking/qspinlock_paravirt.h:508) Hardware name: Red Hat KVM, BIOS 0.5.1 01/01/2011 RIP: 0010:__pv_queued_spin_unlock_slowpath (kernel/locking/qspinlock_paravirt.h:508) Code: 73 56 3a ff 90 c3 cc cc cc cc 8b 05 bb 1f 48 01 85 c0 74 05 c3 cc cc cc cc 8b 17 48 89 fe 48 c7 c7 30 20 ce 8f e8 ad 56 42 ff <0f> 0b c3 cc cc cc cc 0f 0b 0f 1f 40 00 90 90 90 90 90 90 90 90 90 RSP: 0018:ffffa8d200604cb8 EFLAGS: 00010282 RAX: 0000000000000000 RBX: 0000000000000000 RCX: ffff9d1ef60e0908 RDX: 00000000ffffffd8 RSI: 0000000000000027 RDI: ffff9d1ef60e0900 RBP: ffff9d181cd5c280 R08: 0000000000000000 R09: 00000000ffff7fff R10: ffffa8d200604b68 R11: ffffffff907dcdc8 R12: 0000000000000000 R13: ffff9d181cd5c660 R14: ffff9d1813a3f330 R15: 0000000000001000 FS: 00007fa110184640(0000) GS:ffff9d1ef60c0000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000020000000 CR3: 000000011f65e000 CR4: 00000000000006f0 Call Trace: <IRQ> _raw_spin_unlock (kernel/locking/spinlock.c:186) inet_csk_reqsk_queue_add (net/ipv4/inet_connection_sock.c:1321) inet_csk_complete_hashdance (net/ipv4/inet_connection_sock.c:1358) tcp_check_req (net/ipv4/tcp_minisocks.c:868) tcp_v4_rcv (net/ipv4/tcp_ipv4.c:2260) ip_protocol_deliver_rcu (net/ipv4/ip_input.c:205) ip_local_deliver_finish (net/ipv4/ip_input.c:234) __netif_receive_skb_one_core (net/core/dev.c:5529) process_backlog (./include/linux/rcupdate.h:779) __napi_poll (net/core/dev.c:6533) net_rx_action (net/core/dev.c:6604) __do_softirq (./arch/x86/include/asm/jump_label.h:27) do_softirq (kernel/softirq.c:454 kernel/softirq.c:441) </IRQ> <TASK> __local_bh_enable_ip (kernel/softirq.c:381) __dev_queue_xmit (net/core/dev.c:4374) ip_finish_output2 (./include/net/neighbour.h:540 net/ipv4/ip_output.c:235) __ip_queue_xmit (net/ipv4/ip_output.c:535) __tcp_transmit_skb (net/ipv4/tcp_output.c:1462) tcp_rcv_synsent_state_process (net/ipv4/tcp_input.c:6469) tcp_rcv_state_process (net/ipv4/tcp_input.c:6657) tcp_v4_do_rcv (net/ipv4/tcp_ipv4.c:1929) __release_sock (./include/net/sock.h:1121 net/core/sock.c:2968) release_sock (net/core/sock.c:3536) inet_wait_for_connect (net/ipv4/af_inet.c:609) __inet_stream_connect (net/ipv4/af_inet.c:702) inet_stream_connect (net/ipv4/af_inet.c:748) __sys_connect (./include/linux/file.h:45 net/socket.c:2064) __x64_sys_connect (net/socket.c:2073 net/socket.c:2070 net/socket.c:2070) do_syscall_64 (arch/x86/entry/common.c:51 arch/x86/entry/common.c:82) entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:129) RIP: 0033:0x7fa10ff05a3d Code: 5b 41 5c c3 66 0f 1f 84 00 00 00 00 00 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d ab a3 0e 00 f7 d8 64 89 01 48 RSP: 002b:00007fa110183de8 EFLAGS: 00000202 ORIG_RAX: 000000000000002a RAX: ffffffffffffffda RBX: 0000000020000054 RCX: 00007fa10ff05a3d RDX: 000000000000001c RSI: 0000000020000040 RDI: 0000000000000003 RBP: 00007fa110183e20 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000202 R12: 00007fa110184640 R13: 0000000000000000 R14: 00007fa10fe8b060 R15: 00007fff73e23b20 </TASK>
The issue triggering process is analyzed as follows:
Thread A Thread Btcp_v4_rcv //receive ack TCP packet inet_shutdown
tcp_check_req tcp_disconnect //disconnect sock
... tcp_set_state(sk, TCP_CLOSE)
inet_csk_complete_hashdance ...
inet_csk_reqsk_queue_add inet_listen //start listen
spin_lock(&queue->rskq_lock) inet_csk_listen_start
... reqsk_queue_alloc
... spin_lock_init
spin_unlock(&queue->rskq_lock) //warningWhen the socket receives the ACK packet during the three-way handshake, it will hold spinlock. And then the user actively shutdowns the socket and listens to the socket immediately, the spinlock will be initialized. When the socket is going to release the spinlock, a warning is generated. Also the same issue to fastopenq.lock.
Move init spinlock to inet_create and inet_accept to make sure init the accept_queue's spinlocks once.
--- include/net/inet_connection_sock.h | 8 ++++++++ net/core/request_sock.c | 3 --- net/ipv4/af_inet.c | 3 +++ net/ipv4/inet_connection_sock.c | 4 ++++ 4 files changed, 15 insertions(+), 3 deletions(-)
include/net/inet_connection_sock.h +8 -0
@@ -357,4 +357,12 @@ static inline bool inet_csk_has_ulp(const struct sock *sk) return inet_test_bit(IS_ICSK, sk) && !!inet_csk(sk)->icsk_ulp_ops; } +static inline void inet_init_csk_locks (struct sock *sk) +{ +struct inet_connection_sock *icsk =inet_csk (sk); + +spin_lock_init (&icsk->icsk_accept_queue.rskq_lock); +spin_lock_init (&icsk->icsk_accept_queue.fastopenq.lock); +} +#endif /* _INET_CONNECTION_SOCK_H */
net/core/request_sock.c +0 -3
@@ -33,9 +33,6 @@void reqsk_queue_alloc (struct request_sock_queue *queue) { -spin_lock_init (&queue->rskq_lock); - -spin_lock_init (&queue->fastopenq.lock); queue->fastopenq.rskq_rst_head =NULL ; queue->fastopenq.rskq_rst_tail =NULL ; queue->fastopenq.qlen =0 ;
net/ipv4/af_inet.c +3 -0
@@ -330,6 +330,9 @@ static int inet_create(struct net *net, struct socket *sock, int protocol,if (INET_PROTOSW_REUSE & answer_flags) sk->sk_reuse =SK_CAN_REUSE ; +if (INET_PROTOSW_ICSK & answer_flags) +inet_init_csk_locks (sk); + inet =inet_sk (sk);inet_assign_bit (IS_ICSK , sk,INET_PROTOSW_ICSK & answer_flags);
net/ipv4/inet_connection_sock.c +4 -0
@@ -730,6 +730,10 @@ struct sock *inet_csk_accept(struct sock *sk, int flags, int *err, bool kern) }if (req)reqsk_put (req); + +if (newsk) +inet_init_csk_locks (newsk); +return newsk; out_err: newsk =NULL ;
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 151/346 bnxt_en: Wait for FLR to complete during probe
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Chan <[email protected]>
[ Upstream commit 3c1069fa42872f95cf3c6fedf80723d391e12d57 ]
The first message to firmware may fail if the device is undergoing FLR. The driver has some recovery logic for this failure scenario but we must wait 100 msec for FLR to complete before proceeding. Otherwise the recovery will always fail.
--- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/net/ethernet/broadcom/bnxt/bnxt.c +5 -0
@@ -12298,6 +12298,11 @@ static int bnxt_fw_init_one_p1(struct bnxt *bp) bp->fw_cap =0 ; rc =bnxt_hwrm_ver_get (bp); +/* FW may be unresponsive after FLR. FLR must complete within 100 msec +* so wait before continuing with recovery. +*/ +if (rc) +msleep (100 );bnxt_try_map_fw_health_reg (bp);if (rc) { rc =bnxt_try_recover_fw (bp);
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 152/346 bnxt_en: Prevent kernel warning when running offline self test
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Chan <[email protected]>
[ Upstream commit c20f482129a582455f02eb9a6dcb2a4215274599 ]
We call bnxt_half_open_nic() to setup the chip partially to run loopback tests. The rings and buffers are initialized normally so that we can transmit and receive packets in loopback mode. That means page pool buffers are allocated for the aggregation ring just like the normal case. NAPI is not needed because we are just polling for the loopback packets.
When we're done with the loopback tests, we call bnxt_half_close_nic() to clean up. When freeing the page pools, we hit a WARN_ON() in page_pool_unlink_napi() because the NAPI state linked to the page pool is uninitialized.
The simplest way to avoid this warning is just to initialize the NAPIs during half open and delete the NAPIs during half close. Trying to skip the page pool initialization or skip linking of NAPI during half open will be more complicated.
This fix avoids this warning:
WARNING: CPU: 4 PID: 46967 at net/core/page_pool.c:946 page_pool_unlink_napi+0x1f/0x30 CPU: 4 PID: 46967 Comm: ethtool Tainted: G S W 6.7.0-rc5+ #22 Hardware name: Dell Inc. PowerEdge R750/06V45N, BIOS 1.3.8 08/31/2021 RIP: 0010:page_pool_unlink_napi+0x1f/0x30 Code: 90 90 90 90 90 90 90 90 90 90 90 0f 1f 44 00 00 48 8b 47 18 48 85 c0 74 1b 48 8b 50 10 83 e2 01 74 08 8b 40 34 83 f8 ff 74 02 <0f> 0b 48 c7 47 18 00 00 00 00 c3 cc cc cc cc 66 90 90 90 90 90 90 RSP: 0018:ffa000003d0dfbe8 EFLAGS: 00010246 RAX: ff110003607ce640 RBX: ff110010baf5d000 RCX: 0000000000000008 RDX: 0000000000000000 RSI: ff110001e5e522c0 RDI: ff110010baf5d000 RBP: ff11000145539b40 R08: 0000000000000001 R09: ffffffffc063f641 R10: ff110001361eddb8 R11: 000000000040000f R12: 0000000000000001 R13: 000000000000001c R14: ff1100014553a080 R15: 0000000000003fc0 FS: 00007f9301c4f740(0000) GS:ff1100103fd00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f91344fa8f0 CR3: 00000003527cc005 CR4: 0000000000771ef0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 PKRU: 55555554 Call Trace: <TASK> ? __warn+0x81/0x140 ? page_pool_unlink_napi+0x1f/0x30 ? report_bug+0x102/0x200 ? handle_bug+0x44/0x70 ? exc_invalid_op+0x13/0x60 ? asm_exc_invalid_op+0x16/0x20 ? bnxt_free_ring.isra.123+0xb1/0xd0 [bnxt_en] ? page_pool_unlink_napi+0x1f/0x30 page_pool_destroy+0x3e/0x150 bnxt_free_mem+0x441/0x5e0 [bnxt_en] bnxt_half_close_nic+0x2a/0x40 [bnxt_en] bnxt_self_test+0x21d/0x450 [bnxt_en] __dev_ethtool+0xeda/0x2e30 ? native_queued_spin_lock_slowpath+0x17f/0x2b0 ? __link_object+0xa1/0x160 ? _raw_spin_unlock_irqrestore+0x23/0x40 ? __create_object+0x5f/0x90 ? __kmem_cache_alloc_node+0x317/0x3c0 ? dev_ethtool+0x59/0x170 dev_ethtool+0xa7/0x170 dev_ioctl+0xc3/0x530 sock_do_ioctl+0xa8/0xf0 sock_ioctl+0x270/0x310 __x64_sys_ioctl+0x8c/0xc0 do_syscall_64+0x3e/0xf0 entry_SYSCALL_64_after_hwframe+0x6e/0x76
--- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/ethernet/broadcom/bnxt/bnxt.c +3 -0
@@ -10627,10 +10627,12 @@ int bnxt_half_open_nic(struct bnxt *bp)netdev_err (bp->dev,"bnxt_alloc_mem err: %x\n" , rc); goto half_open_err; } +bnxt_init_napi (bp);set_bit (BNXT_STATE_HALF_OPEN , &bp->state); rc =bnxt_init_nic (bp, true);if (rc) {clear_bit (BNXT_STATE_HALF_OPEN , &bp->state); +bnxt_del_napi (bp);netdev_err (bp->dev,"bnxt_init_nic err: %x\n" , rc); goto half_open_err; }
@@ -10649,6 +10651,7 @@ int bnxt_half_open_nic(struct bnxt *bp)void bnxt_half_close_nic (struct bnxt *bp) {bnxt_hwrm_resource_free (bp, false, true); +bnxt_del_napi (bp);bnxt_free_skbs (bp);bnxt_free_mem (bp, true);clear_bit (BNXT_STATE_HALF_OPEN , &bp->state);
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 153/346 vlan: skip nested type that is not IFLA_VLAN_QOS_MAPPING
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lin Ma <[email protected]>
[ Upstream commit 6c21660fe221a15c789dee2bc2fd95516bc5aeaf ]
In the vlan_changelink function, a loop is used to parse the nested attributes IFLA_VLAN_EGRESS_QOS and IFLA_VLAN_INGRESS_QOS in order to obtain the struct ifla_vlan_qos_mapping. These two nested attributes are checked in the vlan_validate_qos_map function, which calls nla_validate_nested_deprecated with the vlan_map_policy.
However, this deprecated validator applies a LIBERAL strictness, allowing the presence of an attribute with the type IFLA_VLAN_QOS_UNSPEC. Consequently, the loop in vlan_changelink may parse an attribute of type IFLA_VLAN_QOS_UNSPEC and believe it carries a payload of struct ifla_vlan_qos_mapping, which is not necessarily true.
To address this issue and ensure compatibility, this patch introduces two type checks that skip attributes whose type is not IFLA_VLAN_QOS_MAPPING.
--- net/8021q/vlan_netlink.c | 4 ++++ 1 file changed, 4 insertions(+)
net/8021q/vlan_netlink.c +4 -0
@@ -118,12 +118,16 @@ static int vlan_changelink(struct net_device *dev, struct nlattr *tb[], }if (data[IFLA_VLAN_INGRESS_QOS ]) {nla_for_each_nested (attr, data[IFLA_VLAN_INGRESS_QOS ], rem) { +if (nla_type (attr) !=IFLA_VLAN_QOS_MAPPING ) +continue ; m =nla_data (attr);vlan_dev_set_ingress_priority (dev, m->to, m->from); } }if (data[IFLA_VLAN_EGRESS_QOS ]) {nla_for_each_nested (attr, data[IFLA_VLAN_EGRESS_QOS ], rem) { +if (nla_type (attr) !=IFLA_VLAN_QOS_MAPPING ) +continue ; m =nla_data (attr); err =vlan_dev_set_egress_priority (dev, m->from, m->to);if (err)
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 154/346 llc: make llc_ui_sendmsg() more robust against bonding changes
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit dad555c816a50c6a6a8a86be1f9177673918c647 ]
syzbot was able to trick llc_ui_sendmsg(), allocating an skb with no headroom, but subsequently trying to push 14 bytes of Ethernet header [1]
Like some others, llc_ui_sendmsg() releases the socket lock before calling sock_alloc_send_skb().
Then it acquires it again, but does not redo all the sanity checks that were performed.
This fix:
- Uses LL_RESERVED_SPACE() to reserve space.
- Check all conditions again after socket lock is held again.
- Do not account Ethernet header for mtu limitation.
[1]
skbuff: skb_under_panic: text:ffff800088baa334 len:1514 put:14 head:ffff0000c9c37000 data:ffff0000c9c36ff2 tail:0x5dc end:0x6c0 dev:bond0
kernel BUG at net/core/skbuff.c:193 !
Internal error: Oops - BUG: 00000000f2000800 [#1] PREEMPT SMP Modules linked in: CPU: 0 PID: 6875 Comm: syz-executor.0 Not tainted 6.7.0-rc8-syzkaller-00101-g0802e17d9aca-dirty #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 11/17/2023 pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : skb_panic net/core/skbuff.c:189 [inline] pc : skb_under_panic+0x13c/0x140 net/core/skbuff.c:203 lr : skb_panic net/core/skbuff.c:189 [inline] lr : skb_under_panic+0x13c/0x140 net/core/skbuff.c:203
sp : ffff800096f97000
x29: ffff800096f97010 x28: ffff80008cc8d668 x27: dfff800000000000
x26: ffff0000cb970c90 x25: 00000000000005dc x24: ffff0000c9c36ff2
x23: ffff0000c9c37000 x22: 00000000000005ea x21: 00000000000006c0
x20: 000000000000000e x19: ffff800088baa334 x18: 1fffe000368261ce
x17: ffff80008e4ed000 x16: ffff80008a8310f8 x15: 0000000000000001
x14: 1ffff00012df2d58 x13: 0000000000000000 x12: 0000000000000000
x11: 0000000000000001 x10: 0000000000ff0100 x9 : e28a51f1087e8400 x8 : e28a51f1087e8400 x7 : ffff80008028f8d0 x6 : 0000000000000000 x5 : 0000000000000001 x4 : 0000000000000001 x3 : ffff800082b78714 x2 : 0000000000000001 x1 : 0000000100000000 x0 : 0000000000000089
Call trace: skb_panic net/core/skbuff.c:189 [inline] skb_under_panic+0x13c/0x140 net/core/skbuff.c:203 skb_push+0xf0/0x108 net/core/skbuff.c:2451 eth_header+0x44/0x1f8 net/ethernet/eth.c:83 dev_hard_header include/linux/netdevice.h:3188 [inline] llc_mac_hdr_init+0x110/0x17c net/llc/llc_output.c:33 llc_sap_action_send_xid_c+0x170/0x344 net/llc/llc_s_ac.c:85 llc_exec_sap_trans_actions net/llc/llc_sap.c:153 [inline] llc_sap_next_state net/llc/llc_sap.c:182 [inline] llc_sap_state_process+0x1ec/0x774 net/llc/llc_sap.c:209 llc_build_and_send_xid_pkt+0x12c/0x1c0 net/llc/llc_sap.c:270 llc_ui_sendmsg+0x7bc/0xb1c net/llc/af_llc.c:997 sock_sendmsg_nosec net/socket.c:730 [inline] __sock_sendmsg net/socket.c:745 [inline] sock_sendmsg+0x194/0x274 net/socket.c:767 splice_to_socket+0x7cc/0xd58 fs/splice.c:881 do_splice_from fs/splice.c:933 [inline] direct_splice_actor+0xe4/0x1c0 fs/splice.c:1142 splice_direct_to_actor+0x2a0/0x7e4 fs/splice.c:1088 do_splice_direct+0x20c/0x348 fs/splice.c:1194 do_sendfile+0x4bc/0xc70 fs/read_write.c:1254 __do_sys_sendfile64 fs/read_write.c:1322 [inline] __se_sys_sendfile64 fs/read_write.c:1308 [inline] __arm64_sys_sendfile64+0x160/0x3b4 fs/read_write.c:1308 __invoke_syscall arch/arm64/kernel/syscall.c:37 [inline] invoke_syscall+0x98/0x2b8 arch/arm64/kernel/syscall.c:51 el0_svc_common+0x130/0x23c arch/arm64/kernel/syscall.c:136 do_el0_svc+0x48/0x58 arch/arm64/kernel/syscall.c:155 el0_svc+0x54/0x158 arch/arm64/kernel/entry-common.c:678 el0t_64_sync_handler+0x84/0xfc arch/arm64/kernel/entry-common.c:696 el0t_64_sync+0x190/0x194 arch/arm64/kernel/entry.S:595 Code: aa1803e6 aa1903e7 a90023f5 94792f6a (d4210000)
--- net/llc/af_llc.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-)
net/llc/af_llc.c +16 -8
@@ -928,14 +928,15 @@ static int llc_ui_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,*/ static int llc_ui_sendmsg (struct socket *sock,struct msghdr *msg,size_t len) { + DECLARE_SOCKADDR(struct sockaddr_llc *, addr, msg->msg_name);struct sock *sk = sock->sk;struct llc_sock *llc =llc_sk (sk); - DECLARE_SOCKADDR(struct sockaddr_llc *, addr, msg->msg_name);int flags = msg->msg_flags;int noblock = flags &MSG_DONTWAIT ; +int rc = -EINVAL , copied =0 , hdrlen, hh_len;struct sk_buff *skb =NULL ; +struct net_device *dev;size_t size =0 ; -int rc = -EINVAL , copied =0 , hdrlen;dprintk ("%s: sending from %02X to %02X\n" , __func__, llc->laddr.lsap, llc->daddr.lsap);
@@ -955,22 +956,29 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)if (rc) goto out; } - hdrlen = llc->dev->hard_header_len +llc_ui_header_len (sk, addr); + dev = llc->dev; + hh_len =LL_RESERVED_SPACE (dev); + hdrlen =llc_ui_header_len (sk, addr); size = hdrlen + len; -if (size > llc->dev->mtu) - size = llc->dev->mtu; + size =min_t (size_t, size,READ_ONCE (dev->mtu)); copied = size - hdrlen; rc = -EINVAL ;if (copied <0 ) goto out;release_sock (sk); - skb =sock_alloc_send_skb (sk, size, noblock, &rc); + skb =sock_alloc_send_skb (sk, hh_len + size, noblock, &rc);lock_sock (sk);if (!skb) goto out; - skb->dev = llc->dev; +if (sock_flag (sk,SOCK_ZAPPED ) || + llc->dev != dev || + hdrlen !=llc_ui_header_len (sk, addr) || + hh_len !=LL_RESERVED_SPACE (dev) || + size >READ_ONCE (dev->mtu)) + goto out; + skb->dev = dev; skb->protocol =llc_proto_type (addr->sllc_arphrd); -skb_reserve (skb, hdrlen); +skb_reserve (skb, hh_len + hdrlen); rc =memcpy_from_msg (skb_put (skb, copied), msg, copied);if (rc) goto out;
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 155/346 llc: Drop support for ETH_P_TR_802_2.
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <[email protected]>
[ Upstream commit e3f9bed9bee261e3347131764e42aeedf1ffea61 ]
syzbot reported an uninit-value bug below. [0]
llc supports ETH_P_802_2 (0x0004) and used to support ETH_P_TR_802_2 (0x0011), and syzbot abused the latter to trigger the bug.
write$tun(r0, &(0x7f0000000040)={@val={0x0, 0x11}, @val, @mpls={[], @llc={@snap={0xaa, 0x1, ')', "90e5dd"}}}}, 0x16)
llc_conn_handler() initialises local variables {saddr,daddr}.mac based on skb in llc_pdu_decode_sa()/llc_pdu_decode_da() and passes them to __llc_lookup().
However, the initialisation is done only when skb->protocol is htons(ETH_P_802_2), otherwise, __llc_lookup_established() and __llc_lookup_listener() will read garbage.
The missing initialisation existed prior to commit 211ed865108e ("net: delete all instances of special processing for token ring").
It removed the part to kick out the token ring stuff but forgot to close the door allowing ETH_P_TR_802_2 packets to sneak into llc_rcv().
Let's remove llc_tr_packet_type and complete the deprecation.
[0]:
BUG: KMSAN: uninit-value in __llc_lookup_established+0xe9d/0xf90 __llc_lookup_established+0xe9d/0xf90 __llc_lookup net/llc/llc_conn.c:611 [inline] llc_conn_handler+0x4bd/0x1360 net/llc/llc_conn.c:791 llc_rcv+0xfbb/0x14a0 net/llc/llc_input.c:206 __netif_receive_skb_one_core net/core/dev.c:5527 [inline] __netif_receive_skb+0x1a6/0x5a0 net/core/dev.c:5641 netif_receive_skb_internal net/core/dev.c:5727 [inline] netif_receive_skb+0x58/0x660 net/core/dev.c:5786 tun_rx_batched+0x3ee/0x980 drivers/net/tun.c:1555 tun_get_user+0x53af/0x66d0 drivers/net/tun.c:2002 tun_chr_write_iter+0x3af/0x5d0 drivers/net/tun.c:2048 call_write_iter include/linux/fs.h:2020 [inline] new_sync_write fs/read_write.c:491 [inline] vfs_write+0x8ef/0x1490 fs/read_write.c:584 ksys_write+0x20f/0x4c0 fs/read_write.c:637 __do_sys_write fs/read_write.c:649 [inline] __se_sys_write fs/read_write.c:646 [inline] __x64_sys_write+0x93/0xd0 fs/read_write.c:646 do_syscall_x64 arch/x86/entry/common.c:51 [inline] do_syscall_64+0x44/0x110 arch/x86/entry/common.c:82 entry_SYSCALL_64_after_hwframe+0x63/0x6b
Local variable daddr created at:
llc_conn_handler+0x53/0x1360 net/llc/llc_conn.c:783 llc_rcv+0xfbb/0x14a0 net/llc/llc_input.c:206 CPU: 1 PID: 5004 Comm: syz-executor994 Not tainted 6.6.0-syzkaller-14500-g1c41041124bd #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/09/2023
--- include/net/llc_pdu.h | 6 ++---- net/llc/llc_core.c | 7 ------- 2 files changed, 2 insertions(+), 11 deletions(-)
include/net/llc_pdu.h +2 -4
@@ -262,8 +262,7 @@ static inline void llc_pdu_header_init(struct sk_buff *skb, u8 type,*/ static inline void llc_pdu_decode_sa (struct sk_buff *skb,u8 *sa) { -if (skb->protocol ==htons (ETH_P_802_2 )) -memcpy (sa,eth_hdr (skb)->h_source,ETH_ALEN ); +memcpy (sa,eth_hdr (skb)->h_source,ETH_ALEN ); }/**
@@ -275,8 +274,7 @@ static inline void llc_pdu_decode_sa(struct sk_buff *skb, u8 *sa)*/ static inline void llc_pdu_decode_da (struct sk_buff *skb,u8 *da) { -if (skb->protocol ==htons (ETH_P_802_2 )) -memcpy (da,eth_hdr (skb)->h_dest,ETH_ALEN ); +memcpy (da,eth_hdr (skb)->h_dest,ETH_ALEN ); }/**
net/llc/llc_core.c +0 -7
@@ -135,22 +135,15 @@ static struct packet_type llc_packet_type __read_mostly = { .func = llc_rcv, }; -static struct packet_type llc_tr_packet_type__read_mostly = { - .type =cpu_to_be16 (ETH_P_TR_802_2 ), - .func = llc_rcv, -}; -static int __init llc_init (void ) {dev_add_pack (&llc_packet_type); -dev_add_pack (&llc_tr_packet_type);return 0 ; } static void __exit llc_exit(void) {dev_remove_pack (&llc_packet_type); -dev_remove_pack (&llc_tr_packet_type); }module_init (llc_init);
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 156/346 udp: fix busy polling
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit a54d51fb2dfb846aedf3751af501e9688db447f5 ]
Generic sk_busy_loop_end() only looks at sk->sk_receive_queue for presence of packets.
Problem is that for UDP sockets after blamed commit, some packets could be present in another queue: udp_sk(sk)->reader_queue
In some cases, a busy poller could spin until timeout expiration, even if some packets are available in udp_sk(sk)->reader_queue.
v3: - make sk_busy_loop_end() nicer (Willem)
v2: - add a READ_ONCE(sk->sk_family) in sk_is_inet() to avoid KCSAN splats.
- add a sk_is_inet() check in sk_is_udp() (Willem feedback)
- add a sk_is_inet() check in sk_is_tcp().
--- include/linux/skmsg.h | 6 ------ include/net/inet_sock.h | 5 ----- include/net/sock.h | 18 +++++++++++++++++- net/core/sock.c | 11 +++++++++-- 4 files changed, 26 insertions(+), 14 deletions(-)
include/linux/skmsg.h +0 -6
@@ -500,12 +500,6 @@ static inline bool sk_psock_strp_enabled(struct sk_psock *psock)return !!psock->saved_data_ready; } -static inline bool sk_is_udp (const struct sock *sk) -{ -return sk->sk_type ==SOCK_DGRAM && - sk->sk_protocol ==IPPROTO_UDP ; -} -#if IS_ENABLED (CONFIG_NET_SOCK_MSG )#define BPF_F_STRPARSER (1UL << 1)
include/net/inet_sock.h +0 -5
@@ -310,11 +310,6 @@ static inline unsigned long inet_cmsg_flags(const struct inet_sock *inet)#define inet_assign_bit (nr, sk, val) \ assign_bit(INET_FLAGS_##nr, &inet_sk(sk)->inet_flags, val) -static inline bool sk_is_inet (struct sock *sk) -{ -return sk->sk_family ==AF_INET || sk->sk_family ==AF_INET6 ; -} -/** * sk_to_full_sk - Access to a full socket * @sk: pointer to a socket
include/net/sock.h +17 -1
@@ -2794,9 +2794,25 @@ static inline void skb_setup_tx_timestamp(struct sk_buff *skb, __u16 tsflags) &skb_shinfo(skb)->tskey); } +static inline bool sk_is_inet (const struct sock *sk) +{ +int family =READ_ONCE (sk->sk_family); + +return family ==AF_INET || family ==AF_INET6 ; +} +static inline bool sk_is_tcp (const struct sock *sk) { -return sk->sk_type ==SOCK_STREAM && sk->sk_protocol ==IPPROTO_TCP ; +return sk_is_inet (sk) && + sk->sk_type ==SOCK_STREAM && + sk->sk_protocol ==IPPROTO_TCP ; +} + +static inline bool sk_is_udp (const struct sock *sk) +{ +return sk_is_inet (sk) && + sk->sk_type ==SOCK_DGRAM && + sk->sk_protocol ==IPPROTO_UDP ; }static inline bool sk_is_stream_unix (const struct sock *sk)
net/core/sock.c +9 -2
@@ -107,6 +107,7 @@#include <linux/interrupt.h> #include <linux/poll.h> #include <linux/tcp.h> +#include <linux/udp.h> #include <linux/init.h> #include <linux/highmem.h> #include <linux/user_namespace.h>
@@ -4148,8 +4149,14 @@ bool sk_busy_loop_end(void *p, unsigned long start_time) {struct sock *sk = p; -return !skb_queue_empty_lockless (&sk->sk_receive_queue) || -sk_busy_loop_timeout (sk, start_time); +if (!skb_queue_empty_lockless (&sk->sk_receive_queue)) +return true; + +if (sk_is_udp (sk) && + !skb_queue_empty_lockless (&udp_sk (sk)->reader_queue)) +return true; + +return sk_busy_loop_timeout (sk, start_time); }EXPORT_SYMBOL (sk_busy_loop_end);#endif /* CONFIG_NET_RX_BUSY_POLL */
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 157/346 idpf: distinguish vports by the dev_port attribute
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michal Schmidt <[email protected]>
[ Upstream commit 359724fa3ab79fbe9f42c6263cddc2afae32eef3 ]
idpf registers multiple netdevs (virtual ports) for one PCI function, but it does not provide a way for userspace to distinguish them with sysfs attributes. Per Documentation/ABI/testing/sysfs-class-net, it is a bug not to set dev_port for independent ports on the same PCI bus, device and function.
Without dev_port set, systemd-udevd's default naming policy attempts to assign the same name ("ens2f0") to all four idpf netdevs on my test system and obviously fails, leaving three of them with the initial eth<N> name.
With this patch, systemd-udevd is able to assign unique names to the netdevs (e.g. "ens2f0", "ens2f0d1", "ens2f0d2", "ens2f0d3").
The Intel-provided out-of-tree idpf driver already sets dev_port. In this patch I chose to do it in the same place in the idpf_cfg_netdev function.
--- drivers/net/ethernet/intel/idpf/idpf_lib.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/ethernet/intel/idpf/idpf_lib.c +2 -0
@@ -783,6 +783,8 @@ static int idpf_cfg_netdev(struct idpf_vport *vport)/* setup watchdog timeout value to be 5 second */ netdev->watchdog_timeo =5 *HZ ; + netdev->dev_port = idx; +/* configure default MTU size */ netdev->min_mtu =ETH_MIN_MTU ; netdev->max_mtu = vport->max_mtu;
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 158/346 net: fix removing a namespace with conflicting altnames
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jakub Kicinski <[email protected]>
[ Upstream commit d09486a04f5da0a812c26217213b89a3b1acf836 ]
Mark reports a BUG() when a net namespace is removed.
kernel BUG at net/core/dev.c:11520!
Physical interfaces moved outside of init_net get "refunded" to init_net when that namespace disappears. The main interface name may get overwritten in the process if it would have conflicted. We need to also discard all conflicting altnames. Recent fixes addressed ensuring that altnames get moved with the main interface, which surfaced this problem.
--- net/core/dev.c | 9 +++++++++ net/core/dev.h | 3 +++ 2 files changed, 12 insertions(+)
net/core/dev.c +9 -0
@@ -11509,6 +11509,7 @@ static struct pernet_operations __net_initdata netdev_net_ops = { static void __net_exit default_device_exit_net(struct net *net) { +struct netdev_name_node *name_node, *tmp;struct net_device *dev, *aux;/* * Push all migratable network devices back to the
@@ -11531,6 +11532,14 @@ static void __net_exit default_device_exit_net(struct net *net)snprintf (fb_name,IFNAMSIZ ,"dev%d" , dev->ifindex);if (netdev_name_in_use (&init_net, fb_name))snprintf (fb_name,IFNAMSIZ ,"dev%%d" ); + +netdev_for_each_altname_safe (dev, name_node, tmp) +if (netdev_name_in_use (&init_net, name_node->name)) { +netdev_name_node_del (name_node); +synchronize_rcu (); +__netdev_name_node_alt_destroy (name_node); + } + err =dev_change_net_namespace (dev, &init_net, fb_name);if (err) { pr_emerg("%s: failed to move %s to init_net: %d\n",
net/core/dev.h +3 -0
@@ -64,6 +64,9 @@ int dev_change_name(struct net_device *dev, const char *newname);#define netdev_for_each_altname (dev, namenode) \ list_for_each_entry((namenode), &(dev)->name_node->list, list) +#define netdev_for_each_altname_safe (dev, namenode, next) \ + list_for_each_entry_safe((namenode), (next), &(dev)->name_node->list, \ + list)int netdev_name_node_alt_create (struct net_device *dev,const char *name);int netdev_name_node_alt_destroy (struct net_device *dev,const char *name);
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 159/346 tun: fix missing dropped counter in tun_xdp_act
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yunjian Wang <[email protected]>
[ Upstream commit 5744ba05e7c4bff8fec133dd0f9e51ddffba92f5 ]
The commit 8ae1aff0b331 ("tuntap: split out XDP logic") includes dropped counter for XDP_DROP, XDP_ABORTED, and invalid XDP actions. Unfortunately, that commit missed the dropped counter when error occurs during XDP_TX and XDP_REDIRECT actions. This patch fixes this issue.
--- drivers/net/tun.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/net/tun.c +6 -2
@@ -1630,13 +1630,17 @@ static int tun_xdp_act(struct tun_struct *tun, struct bpf_prog *xdp_prog,switch (act) {case XDP_REDIRECT : err =xdp_do_redirect (tun->dev, xdp, xdp_prog); -if (err) +if (err) { +dev_core_stats_rx_dropped_inc (tun->dev);return err; + }break ;case XDP_TX : err =tun_xdp_tx (tun->dev, xdp); -if (err <0 ) +if (err <0 ) { +dev_core_stats_rx_dropped_inc (tun->dev);return err; + }break ;case XDP_PASS :break ;
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 160/346 tun: add missing rx stats accounting in tun_xdp_act
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yunjian Wang <[email protected]>
[ Upstream commit f1084c427f55d573fcd5688d9ba7b31b78019716 ]
The TUN can be used as vhost-net backend, and it is necessary to count the packets transmitted from TUN to vhost-net/virtio-net. However, there are some places in the receive path that were not taken into account when using XDP. It would be beneficial to also include new accounting for successfully received bytes using dev_sw_netstats_rx_add.
--- drivers/net/tun.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/tun.c +2 -0
@@ -1634,6 +1634,7 @@ static int tun_xdp_act(struct tun_struct *tun, struct bpf_prog *xdp_prog,dev_core_stats_rx_dropped_inc (tun->dev);return err; } +dev_sw_netstats_rx_add (tun->dev, xdp->data_end - xdp->data);break ;case XDP_TX : err =tun_xdp_tx (tun->dev, xdp);
@@ -1641,6 +1642,7 @@ static int tun_xdp_act(struct tun_struct *tun, struct bpf_prog *xdp_prog,dev_core_stats_rx_dropped_inc (tun->dev);return err; } +dev_sw_netstats_rx_add (tun->dev, xdp->data_end - xdp->data);break ;case XDP_PASS :break ;
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 161/346 dpll: fix broken error path in dpll_pin_alloc(..)
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arkadiusz Kubalewski <[email protected]>
[ Upstream commit b6a11a7fc4d6337f7ea720b9287d1b9749c4eae0 ]
If pin type is not expected, or pin properities failed to allocate memory, the unwind error path shall not destroy pin's xarrays, which were not yet initialized.
Add new goto label and use it to fix broken error path.
Stable-dep-of: 830ead5fb0c5 ("dpll: fix pin dump crash for rebound module")
--- drivers/dpll/dpll_core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/dpll/dpll_core.c +4 -3
@@ -440,7 +440,7 @@ dpll_pin_alloc(u64 clock_id, u32 pin_idx, struct module *module,if (WARN_ON (prop->type <DPLL_PIN_TYPE_MUX || prop->type >DPLL_PIN_TYPE_MAX )) { ret = -EINVAL ; - goto err; + goto err_pin_prop; } pin->prop = prop;refcount_set (&pin->refcount,1 );
@@ -448,11 +448,12 @@ dpll_pin_alloc(u64 clock_id, u32 pin_idx, struct module *module,xa_init_flags (&pin->parent_refs,XA_FLAGS_ALLOC ); ret =xa_alloc (&dpll_pin_xa, &pin->id, pin, xa_limit_16b,GFP_KERNEL );if (ret) - goto err; + goto err_xa_alloc;return pin; -err: +err_xa_alloc:xa_destroy (&pin->dpll_refs);xa_destroy (&pin->parent_refs); +err_pin_prop:kfree (pin);return ERR_PTR (ret); }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 162/346 dpll: fix pin dump crash for rebound module
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arkadiusz Kubalewski <[email protected]>
[ Upstream commit 830ead5fb0c5855ce4d70ba2ed4a673b5f1e7d9b ]
When a kernel module is unbound but the pin resources were not entirely freed (other kernel module instance of the same PCI device have had kept the reference to that pin), and kernel module is again bound, the pin properties would not be updated (the properties are only assigned when memory for the pin is allocated), prop pointer still points to the kernel module memory of the kernel module which was deallocated on the unbind.
If the pin dump is invoked in this state, the result is a kernel crash. Prevent the crash by storing persistent pin properties in dpll subsystem, copy the content from the kernel module when pin is allocated, instead of using memory of the kernel module.
--- drivers/dpll/dpll_core.c | 55 +++++++++++++++++++++++++++++++++++-- drivers/dpll/dpll_core.h | 4 +-- drivers/dpll/dpll_netlink.c | 28 +++++++++---------- 3 files changed, 69 insertions(+), 18 deletions(-)
drivers/dpll/dpll_core.c +53 -2
@@ -424,6 +424,53 @@ void dpll_device_unregister(struct dpll_device *dpll, }EXPORT_SYMBOL_GPL (dpll_device_unregister); +static void dpll_pin_prop_free (struct dpll_pin_properties *prop) +{ +kfree (prop->package_label); +kfree (prop->panel_label); +kfree (prop->board_label); +kfree (prop->freq_supported); +} + +static int dpll_pin_prop_dup (const struct dpll_pin_properties *src, +struct dpll_pin_properties *dst) +{ +memcpy (dst, src,sizeof (*dst)); +if (src->freq_supported && src->freq_supported_num) { +size_t freq_size = src->freq_supported_num * +sizeof (*src->freq_supported); + dst->freq_supported =kmemdup (src->freq_supported, + freq_size,GFP_KERNEL ); +if (!src->freq_supported) +return -ENOMEM ; + } +if (src->board_label) { + dst->board_label =kstrdup (src->board_label,GFP_KERNEL ); +if (!dst->board_label) + goto err_board_label; + } +if (src->panel_label) { + dst->panel_label =kstrdup (src->panel_label,GFP_KERNEL ); +if (!dst->panel_label) + goto err_panel_label; + } +if (src->package_label) { + dst->package_label =kstrdup (src->package_label,GFP_KERNEL ); +if (!dst->package_label) + goto err_package_label; + } + +return 0 ; + +err_package_label: +kfree (dst->panel_label); +err_panel_label: +kfree (dst->board_label); +err_board_label: +kfree (dst->freq_supported); +return -ENOMEM ; +} +static struct dpll_pin *dpll_pin_alloc (u64 clock_id,u32 pin_idx,struct module *module,const struct dpll_pin_properties *prop)
@@ -442,7 +489,9 @@ dpll_pin_alloc(u64 clock_id, u32 pin_idx, struct module *module, ret = -EINVAL ; goto err_pin_prop; } - pin->prop = prop; + ret =dpll_pin_prop_dup (prop, &pin->prop); +if (ret) + goto err_pin_prop;refcount_set (&pin->refcount,1 );xa_init_flags (&pin->dpll_refs,XA_FLAGS_ALLOC );xa_init_flags (&pin->parent_refs,XA_FLAGS_ALLOC );
@@ -453,6 +502,7 @@ dpll_pin_alloc(u64 clock_id, u32 pin_idx, struct module *module, err_xa_alloc:xa_destroy (&pin->dpll_refs);xa_destroy (&pin->parent_refs); +dpll_pin_prop_free (&pin->prop); err_pin_prop:kfree (pin);return ERR_PTR (ret);
@@ -513,6 +563,7 @@ void dpll_pin_put(struct dpll_pin *pin)xa_destroy (&pin->dpll_refs);xa_destroy (&pin->parent_refs);xa_erase (&dpll_pin_xa, pin->id); +dpll_pin_prop_free (&pin->prop);kfree (pin); }mutex_unlock (&dpll_lock);
@@ -635,7 +686,7 @@ int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin,unsigned long i, stop;int ret; -if (WARN_ON (parent->prop->type !=DPLL_PIN_TYPE_MUX )) +if (WARN_ON (parent->prop.type !=DPLL_PIN_TYPE_MUX ))return -EINVAL ; if (WARN_ON(!ops) ||
drivers/dpll/dpll_core.h +2 -2
@@ -44,7 +44,7 @@ struct dpll_device {* @module: module of creator * @dpll_refs: hold referencees to dplls pin was registered with * @parent_refs: hold references to parent pins pin was registered with -* @prop: pointer to pin properties given by registerer +* @prop: pin properties copied from the registerer * @rclk_dev_name: holds name of device when pin can recover clock from it * @refcount: refcount **/
@@ -55,7 +55,7 @@ struct dpll_pin {struct module *module;struct xarray dpll_refs;struct xarray parent_refs; -const struct dpll_pin_properties *prop; +struct dpll_pin_properties prop;refcount_t refcount; };
drivers/dpll/dpll_netlink.c +14 -14
@@ -278,17 +278,17 @@ dpll_msg_add_pin_freq(struct sk_buff *msg, struct dpll_pin *pin,if (nla_put_64bit (msg,DPLL_A_PIN_FREQUENCY ,sizeof (freq), &freq,DPLL_A_PIN_PAD ))return -EMSGSIZE ; -for (fs =0 ; fs < pin->prop->freq_supported_num; fs++) { +for (fs =0 ; fs < pin->prop.freq_supported_num; fs++) { nest =nla_nest_start (msg,DPLL_A_PIN_FREQUENCY_SUPPORTED );if (!nest)return -EMSGSIZE ; - freq = pin->prop->freq_supported[fs].min; + freq = pin->prop.freq_supported[fs].min;if (nla_put_64bit (msg,DPLL_A_PIN_FREQUENCY_MIN ,sizeof (freq), &freq,DPLL_A_PIN_PAD )) {nla_nest_cancel (msg, nest);return -EMSGSIZE ; } - freq = pin->prop->freq_supported[fs].max; + freq = pin->prop.freq_supported[fs].max;if (nla_put_64bit (msg,DPLL_A_PIN_FREQUENCY_MAX ,sizeof (freq), &freq,DPLL_A_PIN_PAD )) {nla_nest_cancel (msg, nest);
@@ -304,9 +304,9 @@ static bool dpll_pin_is_freq_supported(struct dpll_pin *pin, u32 freq) {int fs; -for (fs =0 ; fs < pin->prop->freq_supported_num; fs++) -if (freq >= pin->prop->freq_supported[fs].min && - freq <= pin->prop->freq_supported[fs].max) +for (fs =0 ; fs < pin->prop.freq_supported_num; fs++) +if (freq >= pin->prop.freq_supported[fs].min && + freq <= pin->prop.freq_supported[fs].max)return true;return false; }
@@ -396,7 +396,7 @@ static int dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin, struct netlink_ext_ack *extack) { - const struct dpll_pin_properties *prop = pin->prop; + const struct dpll_pin_properties *prop = &pin->prop;struct dpll_pin_ref *ref;int ret;
@@ -689,7 +689,7 @@ dpll_pin_on_pin_state_set(struct dpll_pin *pin, u32 parent_idx,int ret;if (!(DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE & - pin->prop->capabilities)) { + pin->prop.capabilities)) {NL_SET_ERR_MSG (extack,"state changing is not allowed" );return -EOPNOTSUPP ; }
@@ -725,7 +725,7 @@ dpll_pin_state_set(struct dpll_device *dpll, struct dpll_pin *pin,int ret;if (!(DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE & - pin->prop->capabilities)) { + pin->prop.capabilities)) {NL_SET_ERR_MSG (extack,"state changing is not allowed" );return -EOPNOTSUPP ; }
@@ -752,7 +752,7 @@ dpll_pin_prio_set(struct dpll_device *dpll, struct dpll_pin *pin,int ret;if (!(DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE & - pin->prop->capabilities)) { + pin->prop.capabilities)) {NL_SET_ERR_MSG (extack,"prio changing is not allowed" );return -EOPNOTSUPP ; }
@@ -780,7 +780,7 @@ dpll_pin_direction_set(struct dpll_pin *pin, struct dpll_device *dpll,int ret;if (!(DPLL_PIN_CAPABILITIES_DIRECTION_CAN_CHANGE & - pin->prop->capabilities)) { + pin->prop.capabilities)) {NL_SET_ERR_MSG (extack,"direction changing is not allowed" );return -EOPNOTSUPP ; }
@@ -810,8 +810,8 @@ dpll_pin_phase_adj_set(struct dpll_pin *pin, struct nlattr *phase_adj_attr,int ret; phase_adj =nla_get_s32 (phase_adj_attr); -if (phase_adj > pin->prop->phase_range.max || - phase_adj < pin->prop->phase_range.min) { +if (phase_adj > pin->prop.phase_range.max || + phase_adj < pin->prop.phase_range.min) {NL_SET_ERR_MSG_ATTR (extack, phase_adj_attr,"phase adjust value not supported" );return -EINVAL ;
@@ -995,7 +995,7 @@ dpll_pin_find(u64 clock_id, struct nlattr *mod_name_attr,unsigned long i; xa_for_each_marked(&dpll_pin_xa, i, pin, DPLL_REGISTERED) { - prop = pin->prop; + prop = &pin->prop; cid_match = clock_id ? pin->clock_id == clock_id : true; mod_match = mod_name_attr && module_name(pin->module) ? !nla_strcmp(mod_name_attr,
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 163/346 dpll: fix userspace availability of pins
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arkadiusz Kubalewski <[email protected]>
[ Upstream commit db2ec3c94667eaeecc6a74d96594fab6baf80fdc ]
If parent pin was unregistered but child pin was not, the userspace would see the "zombie" pins - the ones that were registered with a parent pin (dpll_pin_on_pin_register(..)).
Technically those are not available - as there is no dpll device in the system. Do not dump those pins and prevent userspace from any interaction with them. Provide a unified function to determine if the pin is available and use it before acting/responding for user requests.
--- drivers/dpll/dpll_netlink.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-)
drivers/dpll/dpll_netlink.c +27 -2
@@ -525,6 +525,24 @@ __dpll_device_change_ntf(struct dpll_device *dpll)return dpll_device_event_send (DPLL_CMD_DEVICE_CHANGE_NTF , dpll); } +static bool dpll_pin_available (struct dpll_pin *pin) +{ +struct dpll_pin_ref *par_ref; +unsigned long i; + +if (!xa_get_mark (&dpll_pin_xa, pin->id,DPLL_REGISTERED )) +return false; +xa_for_each (&pin->parent_refs, i, par_ref) +if (xa_get_mark (&dpll_pin_xa, par_ref->pin->id, +DPLL_REGISTERED )) +return true; +xa_for_each (&pin->dpll_refs, i, par_ref) +if (xa_get_mark (&dpll_device_xa, par_ref->dpll->id, +DPLL_REGISTERED )) +return true; +return false; +} +/** * dpll_device_change_ntf - notify that the dpll device has been changed * @dpll: registered dpll pointer
@@ -551,7 +569,7 @@ dpll_pin_event_send(enum dpll_cmd event, struct dpll_pin *pin)int ret = -ENOMEM ;void *hdr; -if (WARN_ON (!xa_get_mark (&dpll_pin_xa, pin->id,DPLL_REGISTERED ))) +if (!dpll_pin_available (pin))return -ENODEV ; msg =genlmsg_new (NLMSG_GOODSIZE ,GFP_KERNEL );
@@ -1102,6 +1120,10 @@ int dpll_nl_pin_id_get_doit(struct sk_buff *skb, struct genl_info *info) } pin =dpll_pin_find_from_nlattr (info);if (!IS_ERR (pin)) { +if (!dpll_pin_available (pin)) { +nlmsg_free (msg); +return -ENODEV ; + } ret =dpll_msg_add_pin_handle (msg, pin);if (ret) {nlmsg_free (msg);
@@ -1151,6 +1173,8 @@ int dpll_nl_pin_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)xa_for_each_marked_start (&dpll_pin_xa, i, pin,DPLL_REGISTERED , ctx->idx) { +if (!dpll_pin_available (pin)) +continue ; hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, &dpll_nl_family, NLM_F_MULTI,
@@ -1413,7 +1437,8 @@ int dpll_pin_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, } info->user_ptr[0 ] =xa_load (&dpll_pin_xa,nla_get_u32 (info->attrs[DPLL_A_PIN_ID ])); -if (!info->user_ptr[0 ]) { +if (!info->user_ptr[0 ] || + !dpll_pin_available (info->user_ptr[0 ])) {NL_SET_ERR_MSG (info->extack,"pin not found" ); ret = -ENODEV ; goto unlock_dev;
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 164/346 dpll: fix register pin with unregistered parent pin
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arkadiusz Kubalewski <[email protected]>
[ Upstream commit 7dc5b18ff71bd6f948810ab8a08b6a6ff8b315c5 ]
In case of multiple kernel module instances using the same dpll device:
if only one registers dpll device, then only that one can register directly connected pins with a dpll device. When unregistered parent is responsible for determining if the muxed pin can be registered with it or not, the drivers need to be loaded in serialized order to work correctly - first the driver instance which registers the direct pins needs to be loaded, then the other instances could register muxed type pins.
Allow registration of a pin with a parent even if the parent was not yet registered, thus allow ability for unserialized driver instance load order.
Do not WARN_ON notification for unregistered pin, which can be invoked for described case, instead just return error.
--- drivers/dpll/dpll_core.c | 6 ------ 1 file changed, 6 deletions(-)
drivers/dpll/dpll_core.c +0 -6
@@ -28,8 +28,6 @@ static u32 dpll_xa_id; WARN_ON_ONCE(!xa_get_mark(&dpll_device_xa, (d)->id, DPLL_REGISTERED))#define ASSERT_DPLL_NOT_REGISTERED (d) \ WARN_ON_ONCE(xa_get_mark(&dpll_device_xa, (d)->id, DPLL_REGISTERED)) -#define ASSERT_PIN_REGISTERED (p) \ - WARN_ON_ONCE(!xa_get_mark(&dpll_pin_xa, (p)->id, DPLL_REGISTERED))struct dpll_device_registration {struct list_head list;
@@ -614,8 +612,6 @@ dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin,WARN_ON (!ops->state_on_dpll_get) || WARN_ON(!ops->direction_get)) return -EINVAL; -if (ASSERT_DPLL_REGISTERED (dpll)) -return -EINVAL ;mutex_lock (&dpll_lock); if (WARN_ON(!(dpll->module == pin->module &&
@@ -693,8 +689,6 @@ int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin,WARN_ON (!ops->state_on_pin_get) || WARN_ON(!ops->direction_get)) return -EINVAL; -if (ASSERT_PIN_REGISTERED (parent)) -return -EINVAL ;mutex_lock (&dpll_lock); ret =dpll_xa_ref_pin_add (&pin->parent_refs, parent, ops, priv);
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 165/346 net: micrel: Fix PTP frame parsing for lan8814
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Horatiu Vultur <[email protected]>
[ Upstream commit aaf632f7ab6dec57bc9329a438f94504fe8034b9 ]
The HW has the capability to check each frame if it is a PTP frame, which domain it is, which ptp frame type it is, different ip address in the frame. And if one of these checks fail then the frame is not timestamp. Most of these checks were disabled except checking the field minorVersionPTP inside the PTP header. Meaning that once a partner sends a frame compliant to 8021AS which has minorVersionPTP set to 1, then the frame was not timestamp because the HW expected by default a value of 0 in minorVersionPTP. This is exactly the same issue as on lan8841. Fix this issue by removing this check so the userspace can decide on this.
--- drivers/net/phy/micrel.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
drivers/net/phy/micrel.c +11 -0
@@ -120,6 +120,11 @@*/ #define LAN8814_1PPM_FORMAT 17179 +#define PTP_RX_VERSION 0x0248 +#define PTP_TX_VERSION 0x0288 +#define PTP_MAX_VERSION (x) (((x) & GENMASK(7, 0)) << 8) +#define PTP_MIN_VERSION (x) ((x) & GENMASK(7, 0)) +#define PTP_RX_MOD 0x024F#define PTP_RX_MOD_BAD_UDPV4_CHKSUM_FORCE_FCS_DIS_ BIT(3)#define PTP_RX_TIMESTAMP_EN 0x024D
@@ -3147,6 +3152,12 @@ static void lan8814_ptp_init(struct phy_device *phydev)lanphy_write_page_reg (phydev,5 ,PTP_TX_PARSE_IP_ADDR_EN ,0 );lanphy_write_page_reg (phydev,5 ,PTP_RX_PARSE_IP_ADDR_EN ,0 ); +/* Disable checking for minorVersionPTP field */ +lanphy_write_page_reg (phydev,5 ,PTP_RX_VERSION , +PTP_MAX_VERSION (0xff ) |PTP_MIN_VERSION (0x0 )); +lanphy_write_page_reg (phydev,5 ,PTP_TX_VERSION , +PTP_MAX_VERSION (0xff ) |PTP_MIN_VERSION (0x0 )); +skb_queue_head_init (&ptp_priv->tx_queue);skb_queue_head_init (&ptp_priv->rx_queue);INIT_LIST_HEAD (&ptp_priv->rx_ts_list);
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 166/346 net/rds: Fix UBSAN: array-index-out-of-bounds in rds_cmsg_recv
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sharath Srinivasan <[email protected]>
[ Upstream commit 13e788deb7348cc88df34bed736c3b3b9927ea52 ]
Syzcaller UBSAN crash occurs in rds_cmsg_recv(),
which reads inc->i_rx_lat_trace[j + 1] with index 4 (3 + 1), but with array size of 4 (RDS_RX_MAX_TRACES).
Here 'j' is assigned from rs->rs_rx_trace[i] and in-turn from trace.rx_trace_pos[i] in rds_recv_track_latency(),
with both arrays sized 3 (RDS_MSG_RX_DGRAM_TRACE_MAX). So fix the off-by-one bounds check in rds_recv_track_latency() to prevent a potential crash in rds_cmsg_recv().
Found by syzcaller:
=================================================================
UBSAN: array-index-out-of-bounds in net/rds/recv.c:585:39 index 4 is out of range for type 'u64 [4]' CPU: 1 PID: 8058 Comm: syz-executor228 Not tainted 6.6.0-gd2f51b3516da #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 Call Trace: <TASK> __dump_stack lib/dump_stack.c:88 [inline] dump_stack_lvl+0x136/0x150 lib/dump_stack.c:106 ubsan_epilogue lib/ubsan.c:217 [inline] __ubsan_handle_out_of_bounds+0xd5/0x130 lib/ubsan.c:348 rds_cmsg_recv+0x60d/0x700 net/rds/recv.c:585 rds_recvmsg+0x3fb/0x1610 net/rds/recv.c:716 sock_recvmsg_nosec net/socket.c:1044 [inline] sock_recvmsg+0xe2/0x160 net/socket.c:1066 __sys_recvfrom+0x1b6/0x2f0 net/socket.c:2246 __do_sys_recvfrom net/socket.c:2264 [inline] __se_sys_recvfrom net/socket.c:2260 [inline] __x64_sys_recvfrom+0xe0/0x1b0 net/socket.c:2260 do_syscall_x64 arch/x86/entry/common.c:51 [inline] do_syscall_64+0x40/0x110 arch/x86/entry/common.c:82 entry_SYSCALL_64_after_hwframe+0x63/0x6b ==================================================================
--- net/rds/af_rds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/rds/af_rds.c +1 -1
@@ -419,7 +419,7 @@ static int rds_recv_track_latency(struct rds_sock *rs, sockptr_t optval, rs->rs_rx_traces = trace.rx_traces;for (i =0 ; i < rs->rs_rx_traces; i++) { -if (trace.rx_trace_pos[i] >RDS_MSG_RX_DGRAM_TRACE_MAX ) { +if (trace.rx_trace_pos[i] >=RDS_MSG_RX_DGRAM_TRACE_MAX ) { rs->rs_rx_traces =0 ;return -EFAULT ; }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 167/346 netfs, fscache: Prevent Oops in fscache_put_cache()
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dan Carpenter <[email protected]>
[ Upstream commit 3be0b3ed1d76c6703b9ee482b55f7e01c369cc68 ]
This function dereferences "cache" and then checks if it's IS_ERR_OR_NULL(). Check first, then dereference.
--- fs/fscache/cache.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/fscache/cache.c +2 -1
@@ -179,13 +179,14 @@ EXPORT_SYMBOL(fscache_acquire_cache);void fscache_put_cache (struct fscache_cache *cache,enum fscache_cache_trace where) { -unsigned int debug_id = cache->debug_id; +unsigned int debug_id;bool zero;int ref;if (IS_ERR_OR_NULL (cache))return ; + debug_id = cache->debug_id; zero =__refcount_dec_and_test (&cache->ref, &ref);trace_fscache_cache (debug_id, ref -1 , where);
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 168/346 tracing: Ensure visibility when inserting an element into tracing_map
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Pavlu <[email protected]>
[ Upstream commit 2b44760609e9eaafc9d234a6883d042fc21132a7 ]
Running the following two commands in parallel on a multi-processor AArch64 machine can sporadically produce an unexpected warning about duplicate histogram entries:
$ while true; do
echo hist:key=id.syscall:val=hitcount > \
/sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/trigger
cat /sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/hist
sleep 0.001
done
$ stress-ng --sysbadaddr $(nproc)The warning looks as follows:
[ 2911.172474] ------------[ cut here ]------------ [ 2911.173111] Duplicates detected: 1 [ 2911.173574] WARNING: CPU: 2 PID: 12247 at kernel/trace/tracing_map.c:983 tracing_map_sort_entries+0x3e0/0x408 [ 2911.174702] Modules linked in: iscsi_ibft(E) iscsi_boot_sysfs(E) rfkill(E) af_packet(E) nls_iso8859_1(E) nls_cp437(E) vfat(E) fat(E) ena(E) tiny_power_button(E) qemu_fw_cfg(E) button(E) fuse(E) efi_pstore(E) ip_tables(E) x_tables(E) xfs(E) libcrc32c(E) aes_ce_blk(E) aes_ce_cipher(E) crct10dif_ce(E) polyval_ce(E) polyval_generic(E) ghash_ce(E) gf128mul(E) sm4_ce_gcm(E) sm4_ce_ccm(E) sm4_ce(E) sm4_ce_cipher(E) sm4(E) sm3_ce(E) sm3(E) sha3_ce(E) sha512_ce(E) sha512_arm64(E) sha2_ce(E) sha256_arm64(E) nvme(E) sha1_ce(E) nvme_core(E) nvme_auth(E) t10_pi(E) sg(E) scsi_mod(E) scsi_common(E) efivarfs(E) [ 2911.174738] Unloaded tainted modules: cppc_cpufreq(E):1 [ 2911.180985] CPU: 2 PID: 12247 Comm: cat Kdump: loaded Tainted: G E 6.7.0-default #2 1b58bbb22c97e4399dc09f92d309344f69c44a01 [ 2911.182398] Hardware name: Amazon EC2 c7g.8xlarge/, BIOS 1.0 11/1/2018 [ 2911.183208] pstate: 61400005 (nZCv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--) [ 2911.184038] pc : tracing_map_sort_entries+0x3e0/0x408 [ 2911.184667] lr : tracing_map_sort_entries+0x3e0/0x408 [ 2911.185310] sp : ffff8000a1513900 [ 2911.185750] x29: ffff8000a1513900 x28: ffff0003f272fe80 x27: 0000000000000001 [ 2911.186600] x26: ffff0003f272fe80 x25: 0000000000000030 x24: 0000000000000008 [ 2911.187458] x23: ffff0003c5788000 x22: ffff0003c16710c8 x21: ffff80008017f180 [ 2911.188310] x20: ffff80008017f000 x19: ffff80008017f180 x18: ffffffffffffffff [ 2911.189160] x17: 0000000000000000 x16: 0000000000000000 x15: ffff8000a15134b8 [ 2911.190015] x14: 0000000000000000 x13: 205d373432323154 x12: 5b5d313131333731 [ 2911.190844] x11: 00000000fffeffff x10: 00000000fffeffff x9 : ffffd1b78274a13c [ 2911.191716] x8 : 000000000017ffe8 x7 : c0000000fffeffff x6 : 000000000057ffa8 [ 2911.192554] x5 : ffff0012f6c24ec0 x4 : 0000000000000000 x3 : ffff2e5b72b5d000 [ 2911.193404] x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffff0003ff254480 [ 2911.194259] Call trace: [ 2911.194626] tracing_map_sort_entries+0x3e0/0x408 [ 2911.195220] hist_show+0x124/0x800 [ 2911.195692] seq_read_iter+0x1d4/0x4e8 [ 2911.196193] seq_read+0xe8/0x138 [ 2911.196638] vfs_read+0xc8/0x300 [ 2911.197078] ksys_read+0x70/0x108 [ 2911.197534] __arm64_sys_read+0x24/0x38 [ 2911.198046] invoke_syscall+0x78/0x108 [ 2911.198553] el0_svc_common.constprop.0+0xd0/0xf8 [ 2911.199157] do_el0_svc+0x28/0x40 [ 2911.199613] el0_svc+0x40/0x178 [ 2911.200048] el0t_64_sync_handler+0x13c/0x158 [ 2911.200621] el0t_64_sync+0x1a8/0x1b0 [ 2911.201115] ---[ end trace 0000000000000000 ]---
The problem appears to be caused by CPU reordering of writes issued from __tracing_map_insert().
The check for the presence of an element with a given key in this function is:
val = READ_ONCE(entry->val);
if (val && keys_match(key, val->key, map->key_size)) ...
The write of a new entry is:
elt = get_free_elt(map);
memcpy(elt->key, key, map->key_size);
entry->val = elt;
The "memcpy(elt->key, key, map->key_size);" and "entry->val = elt;" stores may become visible in the reversed order on another CPU. This second CPU might then incorrectly determine that a new key doesn't match an already present val->key and subsequently insert a new element, resulting in a duplicate.
Fix the problem by adding a write barrier between "memcpy(elt->key, key, map->key_size);" and "entry->val = elt;", and for good measure, also use WRITE_ONCE(entry->val, elt) for publishing the element. The sequence pairs with the mentioned "READ_ONCE(entry->val);" and the "val->key" check which has an address dependency.
The barrier is placed on a path executed when adding an element for a new key. Subsequent updates targeting the same key remain unaffected.
Quoted 1 line
From the user's perspective, the issue was introduced by commit
c193707dde77 ("tracing: Remove code which merges duplicates"), which followed commit cbf4100efb8f ("tracing: Add support to detect and avoid duplicates"). The previous code operated differently; it inherently expected potential races which result in duplicates but merged them later when they occurred.
--- kernel/trace/tracing_map.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
kernel/trace/tracing_map.c +6 -1
@@ -574,7 +574,12 @@ __tracing_map_insert(struct tracing_map *map, void *key, bool lookup_only) }memcpy (elt->key, key, map->key_size); - entry->val = elt; +/* +* Ensure the initialization is visible and +* publish the elt. +*/ +smp_wmb (); +WRITE_ONCE (entry->val, elt);atomic64_inc (&map->hits);return entry->val;
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 169/346 afs: Hide silly-rename files from userspace
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
[ Upstream commit 57e9d49c54528c49b8bffe6d99d782ea051ea534 ]
There appears to be a race between silly-rename files being created/removed and various userspace tools iterating over the contents of a directory, leading to such errors as:
find: './kernel/.tmp_cpio_dir/include/dt-bindings/reset/.__afs2080': No such file or directory
tar: ./include/linux/greybus/.__afs3C95: File removed before we read it
when building a kernel.
Fix afs_readdir() so that it doesn't return .__afsXXXX silly-rename files to userspace. This doesn't stop them being looked up directly by name as we need to be able to look them up from within the kernel as part of the silly-rename algorithm.
--- fs/afs/dir.c | 8 ++++++++ 1 file changed, 8 insertions(+)
fs/afs/dir.c +8 -0
@@ -474,6 +474,14 @@ static int afs_dir_iterate_block(struct afs_vnode *dvnode,continue ; } +/* Don't expose silly rename entries to userspace. */ +if (nlen >6 && + dire->u.name[0 ] =='.' && + ctx->actor != afs_lookup_filldir && + ctx->actor != afs_lookup_one_filldir && +memcmp (dire->u.name,".__afs" ,6 ) ==0 ) +continue ; +/* found the next entry */ if (!dir_emit(ctx, dire->u.name, nlen, ntohl(dire->u.vnode),
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 170/346 afs: fix the usage of read_seqbegin_or_lock() in afs_find_server*()
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Oleg Nesterov <[email protected]>
[ Upstream commit 1702e0654ca9a7bcd7c7619c8a5004db58945b71 ]
David Howells says:
(5) afs_find_server().
There could be a lot of servers in the list and each server can have multiple addresses, so I think this would be better with an exclusive second pass.
The server list isn't likely to change all that often, but when it does change, there's a good chance several servers are going to be added/removed one after the other. Further, this is only going to be used for incoming cache management/callback requests from the server, which hopefully aren't going to happen too often - but it is remotely drivable.
(6) afs_find_server_by_uuid().
Similarly to (5), there could be a lot of servers to search through, but they are in a tree not a flat list, so it should be faster to process. Again, it's not likely to change that often and, again, when it does change it's likely to involve multiple changes. This can be driven remotely by an incoming cache management request but is mostly going to be driven by setting up or reconfiguring a volume's server list - something that also isn't likely to happen often.
Make the "seq" counter odd on the 2nd pass, otherwise read_seqbegin_or_lock() never takes the lock.
Stable-dep-of: 17ba6f0bd14f ("afs: Fix error handling with lookup via FS.InlineBulkStatus")
--- fs/afs/server.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
fs/afs/server.c +4 -3
@@ -27,7 +27,7 @@ struct afs_server *afs_find_server(struct afs_net *net,const struct afs_addr_list *alist;struct afs_server *server =NULL ;unsigned int i; -int seq =0 , diff; +int seq =1 , diff;rcu_read_lock ();
@@ -35,6 +35,7 @@ struct afs_server *afs_find_server(struct afs_net *net,if (server)afs_unuse_server_notime (net, server, afs_server_trace_put_find_rsq); server =NULL ; + seq++;/* 2 on the 1st/lockless path, otherwise odd */ read_seqbegin_or_lock (&net->fs_addr_lock, &seq);if (srx->transport.family ==AF_INET6 ) {
@@ -90,7 +91,7 @@ struct afs_server *afs_find_server_by_uuid(struct afs_net *net, const uuid_t *uu {struct afs_server *server =NULL ;struct rb_node *p; -int diff, seq =0 ; +int diff, seq =1 ;_enter ("%pU" , uuid);
@@ -102,7 +103,7 @@ struct afs_server *afs_find_server_by_uuid(struct afs_net *net, const uuid_t *uuif (server)afs_unuse_server (net, server, afs_server_trace_put_uuid_rsq); server =NULL ; - + seq++;/* 2 on the 1st/lockless path, otherwise odd */ read_seqbegin_or_lock (&net->fs_lock, &seq); p = net->fs_servers.rb_node;
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 171/346 afs: Add comments on abort handling
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
[ Upstream commit fe245c8fcdac339e6b42076c828a6bede3a5e948 ]
Add some comments on AFS abort code handling in the rotation algorithm and adjust the errors produced to match.
Stable-dep-of: 17ba6f0bd14f ("afs: Fix error handling with lookup via FS.InlineBulkStatus")
--- fs/afs/rotate.c | 101 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 90 insertions(+), 11 deletions(-)
fs/afs/rotate.c +90 -11
@@ -13,6 +13,7 @@#include <linux/sched/signal.h> #include "internal.h" #include "afs_fs.h" +#include "protocol_uae.h" /* * Begin iteration through a server list, starting with the vnode's last used
@@ -143,6 +144,11 @@ bool afs_select_fileserver(struct afs_operation *op)case -ECONNABORTED :/* The far side rejected the operation on some grounds. This * might involve the server being busy or the volume having been moved. +* +* Note that various V* errors should not be sent to a cache manager +* by a fileserver as they should be translated to more modern UAE* +* errors instead. IBM AFS and OpenAFS fileservers, however, do leak +* these abort codes. */ switch (op->ac.abort_code) {case VNOVOL :
@@ -150,6 +156,11 @@ bool afs_select_fileserver(struct afs_operation *op)* - May indicate that the VL is wrong - retry once and compare * the results. * - May indicate that the fileserver couldn't attach to the vol. +* - The volume might have been temporarily removed so that it can +* be replaced by a volume restore. "vos" might have ended one +* transaction and has yet to create the next. +* - The volume might not be blessed or might not be in-service +* (administrative action). */ if (op->flags &AFS_OPERATION_VNOVOL ) { op->error = -EREMOTEIO ;
@@ -183,16 +194,56 @@ bool afs_select_fileserver(struct afs_operation *op)_leave (" = t [vnovol]" );return true; -case VSALVAGE :/* TODO: Should this return an error or iterate? */ case VVOLEXISTS : -case VNOSERVICE :case VONLINE : -case VDISKFULL : -case VOVERQUOTA : - op->error =afs_abort_to_error (op->ac.abort_code); +/* These should not be returned from the fileserver. */ +pr_warn ("Fileserver returned unexpected abort %d\n" , + op->ac.abort_code); + op->error = -EREMOTEIO ; + goto next_server; + +case VNOSERVICE : +/* Prior to AFS 3.2 VNOSERVICE was returned from the fileserver +* if the volume was neither in-service nor administratively +* blessed. All usage was replaced by VNOVOL because AFS 3.1 and +* earlier cache managers did not handle VNOSERVICE and assumed +* it was the client OSes errno 105. +* +* Starting with OpenAFS 1.4.8 VNOSERVICE was repurposed as the +* fileserver idle dead time error which was sent in place of +* RX_CALL_TIMEOUT (-3). The error was intended to be sent if the +* fileserver took too long to send a reply to the client. +* RX_CALL_TIMEOUT would have caused the cache manager to mark the +* server down whereas VNOSERVICE since AFS 3.2 would cause cache +* manager to temporarily (up to 15 minutes) mark the volume +* instance as unusable. +* +* The idle dead logic resulted in cache inconsistency since a +* state changing call that the cache manager assumed was dead +* could still be processed to completion by the fileserver. This +* logic was removed in OpenAFS 1.8.0 and VNOSERVICE is no longer +* returned. However, many 1.4.8 through 1.6.24 fileservers are +* still in existence. +* +* AuriStorFS fileservers have never returned VNOSERVICE. +* +* VNOSERVICE should be treated as an alias for RX_CALL_TIMEOUT. +*/ +case RX_CALL_TIMEOUT : + op->error = -ETIMEDOUT ; goto next_server; +case VSALVAGING :/* This error should not be leaked to cache managers +* but is from OpenAFS demand attach fileservers. +* It should be treated as an alias for VOFFLINE. +*/ +case VSALVAGE :/* VSALVAGE should be treated as a synonym of VOFFLINE */ case VOFFLINE : +/* The volume is in use by the volserver or another volume utility +* for an operation that might alter the contents. The volume is +* expected to come back but it might take a long time (could be +* days). +*/ if (!test_and_set_bit (AFS_VOLUME_OFFLINE , &op->volume->flags)) {afs_busy (op->volume, op->ac.abort_code);clear_bit (AFS_VOLUME_BUSY , &op->volume->flags);
@@ -207,11 +258,20 @@ bool afs_select_fileserver(struct afs_operation *op) } goto busy; -case VSALVAGING : -case VRESTARTING : +case VRESTARTING :/* The fileserver is either shutting down or starting up. */ case VBUSY : -/* Retry after going round all the servers unless we -* have a file lock we need to maintain. +/* The volume is in use by the volserver or another volume +* utility for an operation that is not expected to alter the +* contents of the volume. VBUSY does not need to be returned +* for a ROVOL or BACKVOL bound to an ITBusy volserver +* transaction. The fileserver is permitted to continue serving +* content from ROVOLs and BACKVOLs during an ITBusy transaction +* because the content will not change. However, many fileserver +* releases do return VBUSY for ROVOL and BACKVOL instances under +* many circumstances. +* +* Retry after going round all the servers unless we have a file +* lock we need to maintain. */ if (op->flags &AFS_OPERATION_NO_VSLEEP ) { op->error = -EBUSY ;
@@ -226,7 +286,7 @@ bool afs_select_fileserver(struct afs_operation *op)if (!afs_sleep_and_retry (op)) goto failed; -/* Retry with same server & address */ +/* Retry with same server & address */ _leave (" = t [vbusy]" );return true; }
@@ -270,10 +330,29 @@ bool afs_select_fileserver(struct afs_operation *op) goto restart_from_beginning; +case VDISKFULL : +case UAENOSPC : +/* The partition is full. Only applies to RWVOLs. +* Translate locally and return ENOSPC. +* No replicas to failover to. +*/ + op->error = -ENOSPC ; + goto failed_but_online; + +case VOVERQUOTA : +case UAEDQUOT : +/* Volume is full. Only applies to RWVOLs. +* Translate locally and return EDQUOT. +* No replicas to failover to. +*/ + op->error = -EDQUOT ; + goto failed_but_online; +default : + op->error =afs_abort_to_error (op->ac.abort_code); + failed_but_online:clear_bit (AFS_VOLUME_OFFLINE , &op->volume->flags);clear_bit (AFS_VOLUME_BUSY , &op->volume->flags); - op->error =afs_abort_to_error (op->ac.abort_code); goto failed; }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 172/346 afs: Turn the afs_addr_list address array into an array of structs
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
[ Upstream commit 07f3502b33a260f873e35708d2fa693eb52225cb ]
Turn the afs_addr_list address array into an array of structs, thereby allowing per-address (such as RTT) info to be added.
Stable-dep-of: 17ba6f0bd14f ("afs: Fix error handling with lookup via FS.InlineBulkStatus")
--- fs/afs/addr_list.c | 10 +++++----- fs/afs/fs_probe.c | 6 +++--- fs/afs/internal.h | 6 +++++- fs/afs/proc.c | 4 ++-- fs/afs/rotate.c | 2 +- fs/afs/rxrpc.c | 4 ++-- fs/afs/server.c | 4 ++-- fs/afs/vl_alias.c | 4 ++-- fs/afs/vl_probe.c | 6 +++--- fs/afs/vl_rotate.c | 2 +- 10 files changed, 26 insertions(+), 22 deletions(-)
fs/afs/addr_list.c +5 -5
@@ -45,7 +45,7 @@ struct afs_addr_list *afs_alloc_addrlist(unsigned int nr, alist->max_addrs = nr;for (i =0 ; i < nr; i++) { -struct sockaddr_rxrpc *srx = &alist->addrs[i]; +struct sockaddr_rxrpc *srx = &alist->addrs[i].srx; srx->srx_family =AF_RXRPC ; srx->srx_service = service; srx->transport_type =SOCK_DGRAM ;
@@ -281,7 +281,7 @@ void afs_merge_fs_addr4(struct afs_addr_list *alist, __be32 xdr, u16 port)return ;for (i =0 ; i < alist->nr_ipv4; i++) { -struct sockaddr_in *a = &alist->addrs[i].transport.sin; +struct sockaddr_in *a = &alist->addrs[i].srx.transport.sin;u32 a_addr =ntohl (a->sin_addr.s_addr);u16 a_port =ntohs (a->sin_port);
@@ -298,7 +298,7 @@ void afs_merge_fs_addr4(struct afs_addr_list *alist, __be32 xdr, u16 port) alist->addrs + i, sizeof(alist->addrs[0]) * (alist->nr_addrs - i)); - srx = &alist->addrs[i]; + srx = &alist->addrs[i].srx; srx->srx_family =AF_RXRPC ; srx->transport_type =SOCK_DGRAM ; srx->transport_len =sizeof (srx->transport.sin);
@@ -321,7 +321,7 @@ void afs_merge_fs_addr6(struct afs_addr_list *alist, __be32 *xdr, u16 port)return ;for (i = alist->nr_ipv4; i < alist->nr_addrs; i++) { -struct sockaddr_in6 *a = &alist->addrs[i].transport.sin6; +struct sockaddr_in6 *a = &alist->addrs[i].srx.transport.sin6;u16 a_port =ntohs (a->sin6_port); diff =memcmp (xdr, &a->sin6_addr,16 );
@@ -338,7 +338,7 @@ void afs_merge_fs_addr6(struct afs_addr_list *alist, __be32 *xdr, u16 port) alist->addrs + i, sizeof(alist->addrs[0]) * (alist->nr_addrs - i)); - srx = &alist->addrs[i]; + srx = &alist->addrs[i].srx; srx->srx_family =AF_RXRPC ; srx->transport_type =SOCK_DGRAM ; srx->transport_len =sizeof (srx->transport.sin6);
fs/afs/fs_probe.c +3 -3
@@ -153,12 +153,12 @@ void afs_fileserver_probe_result(struct afs_call *call)if (call->service_id ==YFS_FS_SERVICE ) { server->probe.is_yfs = true;set_bit (AFS_SERVER_FL_IS_YFS , &server->flags); - alist->addrs[index].srx_service = call->service_id; + alist->addrs[index].srx.srx_service = call->service_id; }else { server->probe.not_yfs = true;if (!server->probe.is_yfs) {clear_bit (AFS_SERVER_FL_IS_YFS , &server->flags); - alist->addrs[index].srx_service = call->service_id; + alist->addrs[index].srx.srx_service = call->service_id; } cap0 =ntohl (call->tmp);if (cap0 &AFS3_VICED_CAPABILITY_64BITFILES )
@@ -182,7 +182,7 @@ void afs_fileserver_probe_result(struct afs_call *call)spin_unlock (&server->probe_lock);_debug ("probe %pU [%u] %pISpc rtt=%u ret=%d" , - &server->uuid, index, &alist->addrs[index].transport, + &server->uuid, index, &alist->addrs[index].srx.transport, rtt_us, ret);return afs_done_one_fs_probe (call->net, server);
fs/afs/internal.h +5 -1
@@ -87,7 +87,9 @@ struct afs_addr_list { enum dns_lookup_status status:8;unsigned long failed;/* Mask of addrs that failed locally/ICMP */ unsigned long responded;/* Mask of addrs that responded */ - struct sockaddr_rxrpc addrs[] __counted_by(max_addrs); +struct { +struct sockaddr_rxrpc srx; + } addrs[] __counted_by(max_addrs);#define AFS_MAX_ADDRESSES ((unsigned int)(sizeof(unsigned long) * 8)) };
@@ -969,6 +971,8 @@ extern void afs_put_addrlist(struct afs_addr_list *);extern struct afs_vlserver_list *afs_parse_text_addrs (struct afs_net *,const char *,size_t ,char ,unsigned short ,unsigned short ); +bool afs_addr_list_same (const struct afs_addr_list *a, +const struct afs_addr_list *b);extern struct afs_vlserver_list *afs_dns_query (struct afs_cell *,time64_t *);extern bool afs_iterate_addresses (struct afs_addr_cursor *);extern int afs_end_cursor (struct afs_addr_cursor *);
fs/afs/proc.c +2 -2
@@ -307,7 +307,7 @@ static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)for (i =0 ; i < alist->nr_addrs; i++)seq_printf (m," %c %pISpc\n" , alist->preferred == i ?'>' :'-' , - &alist->addrs[i].transport); + &alist->addrs[i].srx.transport); }seq_printf (m," info: fl=%lx rtt=%d\n" , vlserver->flags, vlserver->rtt); seq_printf(m, " probe: fl=%x e=%d ac=%d out=%d\n",
@@ -399,7 +399,7 @@ static int afs_proc_servers_show(struct seq_file *m, void *v) alist->version, alist->responded, alist->failed);for (i =0 ; i < alist->nr_addrs; i++)seq_printf (m," [%x] %pISpc%s\n" , - i, &alist->addrs[i].transport, + i, &alist->addrs[i].srx.transport, alist->preferred == i ?"*" :"" );return 0 ; }
fs/afs/rotate.c +1 -1
@@ -488,7 +488,7 @@ bool afs_select_fileserver(struct afs_operation *op)_debug ("address [%u] %u/%u %pISp" , op->index, op->ac.index, op->ac.alist->nr_addrs, - &op->ac.alist->addrs[op->ac.index].transport); + &op->ac.alist->addrs[op->ac.index].srx.transport);_leave (" = t" );return true;
fs/afs/rxrpc.c +2 -2
@@ -296,7 +296,7 @@ static void afs_notify_end_request_tx(struct sock *sock,*/ void afs_make_call (struct afs_addr_cursor *ac,struct afs_call *call,gfp_t gfp) { -struct sockaddr_rxrpc *srx = &ac->alist->addrs[ac->index]; +struct sockaddr_rxrpc *srx = &ac->alist->addrs[ac->index].srx;struct rxrpc_call *rxcall;struct msghdr msg;struct kvec iov[1 ];
@@ -461,7 +461,7 @@ static void afs_log_error(struct afs_call *call, s32 remote_abort) max = m +1 ;pr_notice ("kAFS: Peer reported %s failure on %s [%pISp]\n" , msg, call->type->name, - &call->alist->addrs[call->addr_ix].transport); + &call->alist->addrs[call->addr_ix].srx.transport); } }
fs/afs/server.c +2 -2
@@ -43,7 +43,7 @@ struct afs_server *afs_find_server(struct afs_net *net,hlist_for_each_entry_rcu (server, &net->fs_addresses6, addr6_link) { alist =rcu_dereference (server->addresses);for (i = alist->nr_ipv4; i < alist->nr_addrs; i++) { - b = &alist->addrs[i].transport.sin6; + b = &alist->addrs[i].srx.transport.sin6; diff = ((u16 __force )a->sin6_port - (u16 __force )b->sin6_port);if (diff ==0 )
@@ -59,7 +59,7 @@ struct afs_server *afs_find_server(struct afs_net *net,hlist_for_each_entry_rcu (server, &net->fs_addresses4, addr4_link) { alist =rcu_dereference (server->addresses);for (i =0 ; i < alist->nr_ipv4; i++) { - b = &alist->addrs[i].transport.sin; + b = &alist->addrs[i].srx.transport.sin; diff = ((u16 __force )a->sin_port - (u16 __force )b->sin_port);if (diff ==0 )
fs/afs/vl_alias.c +2 -2
@@ -94,8 +94,8 @@ static int afs_compare_fs_alists(const struct afs_server *server_a, lb =rcu_dereference (server_b->addresses);while (a < la->nr_addrs && b < lb->nr_addrs) { -const struct sockaddr_rxrpc *srx_a = &la->addrs[a]; -const struct sockaddr_rxrpc *srx_b = &lb->addrs[b]; +const struct sockaddr_rxrpc *srx_a = &la->addrs[a].srx; +const struct sockaddr_rxrpc *srx_b = &lb->addrs[b].srx;int diff =afs_compare_addrs (srx_a, srx_b);if (diff <0 ) {
fs/afs/vl_probe.c +3 -3
@@ -106,12 +106,12 @@ void afs_vlserver_probe_result(struct afs_call *call)if (call->service_id ==YFS_VL_SERVICE ) { server->probe.flags |=AFS_VLSERVER_PROBE_IS_YFS ;set_bit (AFS_VLSERVER_FL_IS_YFS , &server->flags); - alist->addrs[index].srx_service = call->service_id; + alist->addrs[index].srx.srx_service = call->service_id; }else { server->probe.flags |=AFS_VLSERVER_PROBE_NOT_YFS ;if (!(server->probe.flags &AFS_VLSERVER_PROBE_IS_YFS )) {clear_bit (AFS_VLSERVER_FL_IS_YFS , &server->flags); - alist->addrs[index].srx_service = call->service_id; + alist->addrs[index].srx.srx_service = call->service_id; } }
@@ -131,7 +131,7 @@ void afs_vlserver_probe_result(struct afs_call *call)spin_unlock (&server->probe_lock);_debug ("probe [%u][%u] %pISpc rtt=%u ret=%d" , - server_index, index, &alist->addrs[index].transport, rtt_us, ret); + server_index, index, &alist->addrs[index].srx.transport, rtt_us, ret);afs_done_one_vl_probe (server, have_result); }
fs/afs/vl_rotate.c +1 -1
@@ -249,7 +249,7 @@ bool afs_select_vlserver(struct afs_vl_cursor *vc)_debug ("VL address %d/%d" , vc->ac.index, vc->ac.alist->nr_addrs); -_leave (" = t %pISpc" , &vc->ac.alist->addrs[vc->ac.index].transport); +_leave (" = t %pISpc" , &vc->ac.alist->addrs[vc->ac.index].srx.transport);return true; next_server:
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 173/346 rxrpc, afs: Allow afs to pin rxrpc_peer objects
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
[ Upstream commit 72904d7b9bfbf2dd146254edea93958bc35bbbfe ]
Change rxrpc's API such that:
(1) A new function, rxrpc_kernel_lookup_peer(), is provided to look up an rxrpc_peer record for a remote address and a corresponding function, rxrpc_kernel_put_peer(), is provided to dispose of it again.
(2) When setting up a call, the rxrpc_peer object used during a call is now passed in rather than being set up by rxrpc_connect_call(). For afs, this meenat passing it to rxrpc_kernel_begin_call() rather than the full address (the service ID then has to be passed in as a separate parameter).
(3) A new function, rxrpc_kernel_remote_addr(), is added so that afs can get a pointer to the transport address for display purposed, and another, rxrpc_kernel_remote_srx(), to gain a pointer to the full rxrpc address.
(4) The function to retrieve the RTT from a call, rxrpc_kernel_get_srtt(), is then altered to take a peer. This now returns the RTT or -1 if there are insufficient samples.
(5) Rename rxrpc_kernel_get_peer() to rxrpc_kernel_call_get_peer().
(6) Provide a new function, rxrpc_kernel_get_peer(), to get a ref on a peer the caller already has.
This allows the afs filesystem to pin the rxrpc_peer records that it is using, allowing faster lookups and pointer comparisons rather than comparing sockaddr_rxrpc contents. It also makes it easier to get hold of the RTT. The following changes are made to afs:
(1) The addr_list struct's addrs[] elements now hold a peer struct pointer and a service ID rather than a sockaddr_rxrpc.
(2) When displaying the transport address, rxrpc_kernel_remote_addr() is used.
(3) The port arg is removed from afs_alloc_addrlist() since it's always overridden.
(4) afs_merge_fs_addr4() and afs_merge_fs_addr6() do peer lookup and may now return an error that must be handled.
(5) afs_find_server() now takes a peer pointer to specify the address.
(6) afs_find_server(), afs_compare_fs_alists() and afs_merge_fs_addr[46]{} now do peer pointer comparison rather than address comparison.
Stable-dep-of: 17ba6f0bd14f ("afs: Fix error handling with lookup via FS.InlineBulkStatus")
--- fs/afs/addr_list.c | 125 ++++++++++++++++++----------------- fs/afs/cmservice.c | 5 +- fs/afs/fs_probe.c | 11 +-- fs/afs/internal.h | 26 ++++---- fs/afs/proc.c | 9 +-- fs/afs/rotate.c | 6 +- fs/afs/rxrpc.c | 10 +-- fs/afs/server.c | 41 ++---------- fs/afs/vl_alias.c | 55 +-------------- fs/afs/vl_list.c | 15 +++-- fs/afs/vl_probe.c | 12 ++-- fs/afs/vl_rotate.c | 6 +- fs/afs/vlclient.c | 22 ++++-- include/net/af_rxrpc.h | 15 +++-- include/trace/events/rxrpc.h | 3 + net/rxrpc/af_rxrpc.c | 62 ++++++++++++++--- net/rxrpc/ar-internal.h | 2 +- net/rxrpc/call_object.c | 17 ++--- net/rxrpc/peer_object.c | 58 ++++++++++------ net/rxrpc/sendmsg.c | 11 ++- 20 files changed, 273 insertions(+), 238 deletions(-)
fs/afs/addr_list.c +66 -59
@@ -13,26 +13,33 @@#include "internal.h" #include "afs_fs.h" +static void afs_free_addrlist (struct rcu_head *rcu) +{ + struct afs_addr_list *alist = container_of(rcu, struct afs_addr_list, rcu); +unsigned int i; + +for (i =0 ; i < alist->nr_addrs; i++) +rxrpc_kernel_put_peer (alist->addrs[i].peer); +} +/* * Release an address list. */ void afs_put_addrlist (struct afs_addr_list *alist) {if (alist &&refcount_dec_and_test (&alist->usage)) -kfree_rcu (alist, rcu); +call_rcu (&alist->rcu, afs_free_addrlist); }/* * Allocate an address list. */ -struct afs_addr_list *afs_alloc_addrlist (unsigned int nr, -unsigned short service, -unsigned short port) +struct afs_addr_list *afs_alloc_addrlist (unsigned int nr,u16 service_id) {struct afs_addr_list *alist;unsigned int i; -_enter ("%u,%u,%u" , nr, service, port); +_enter ("%u,%u" , nr, service_id);if (nr >AFS_MAX_ADDRESSES ) nr =AFS_MAX_ADDRESSES ;
@@ -44,16 +51,8 @@ struct afs_addr_list *afs_alloc_addrlist(unsigned int nr,refcount_set (&alist->usage,1 ); alist->max_addrs = nr; -for (i =0 ; i < nr; i++) { -struct sockaddr_rxrpc *srx = &alist->addrs[i].srx; - srx->srx_family =AF_RXRPC ; - srx->srx_service = service; - srx->transport_type =SOCK_DGRAM ; - srx->transport_len =sizeof (srx->transport.sin6); - srx->transport.sin6.sin6_family =AF_INET6 ; - srx->transport.sin6.sin6_port =htons (port); - } - +for (i =0 ; i < nr; i++) + alist->addrs[i].service_id = service_id;return alist; }
@@ -126,7 +125,7 @@ struct afs_vlserver_list *afs_parse_text_addrs(struct afs_net *net,if (!vllist->servers[0 ].server) goto error_vl; - alist =afs_alloc_addrlist (nr, service,AFS_VL_PORT ); + alist =afs_alloc_addrlist (nr, service);if (!alist) goto error;
@@ -197,9 +196,11 @@ struct afs_vlserver_list *afs_parse_text_addrs(struct afs_net *net, }if (family ==AF_INET ) -afs_merge_fs_addr4 (alist, x[0 ], xport); + ret =afs_merge_fs_addr4 (net, alist, x[0 ], xport);else -afs_merge_fs_addr6 (alist, x, xport); + ret =afs_merge_fs_addr6 (net, alist, x, xport); +if (ret <0 ) + goto error; }while (p < end);
@@ -271,25 +272,33 @@ struct afs_vlserver_list *afs_dns_query(struct afs_cell *cell, time64_t *_expiry/* * Merge an IPv4 entry into a fileserver address list. */ -void afs_merge_fs_addr4 (struct afs_addr_list *alist,__be32 xdr,u16 port) +int afs_merge_fs_addr4 (struct afs_net *net,struct afs_addr_list *alist, +__be32 xdr,u16 port) { -struct sockaddr_rxrpc *srx; -u32 addr =ntohl (xdr); +struct sockaddr_rxrpc srx; +struct rxrpc_peer *peer;int i;if (alist->nr_addrs >= alist->max_addrs) -return ; +return 0 ; -for (i =0 ; i < alist->nr_ipv4; i++) { -struct sockaddr_in *a = &alist->addrs[i].srx.transport.sin; -u32 a_addr =ntohl (a->sin_addr.s_addr); -u16 a_port =ntohs (a->sin_port); + srx.srx_family =AF_RXRPC ; + srx.transport_type =SOCK_DGRAM ; + srx.transport_len =sizeof (srx.transport.sin); + srx.transport.sin.sin_family =AF_INET ; + srx.transport.sin.sin_port =htons (port); + srx.transport.sin.sin_addr.s_addr = xdr; -if (addr == a_addr && port == a_port) -return ; -if (addr == a_addr && port < a_port) -break ; -if (addr < a_addr) + peer =rxrpc_kernel_lookup_peer (net->socket, &srx,GFP_KERNEL ); +if (!peer) +return -ENOMEM ; + +for (i =0 ; i < alist->nr_ipv4; i++) { +if (peer == alist->addrs[i].peer) { +rxrpc_kernel_put_peer (peer); +return 0 ; + } +if (peer <= alist->addrs[i].peer)break ; }
@@ -298,38 +307,42 @@ void afs_merge_fs_addr4(struct afs_addr_list *alist, __be32 xdr, u16 port) alist->addrs + i, sizeof(alist->addrs[0]) * (alist->nr_addrs - i)); - srx = &alist->addrs[i].srx; - srx->srx_family =AF_RXRPC ; - srx->transport_type =SOCK_DGRAM ; - srx->transport_len =sizeof (srx->transport.sin); - srx->transport.sin.sin_family =AF_INET ; - srx->transport.sin.sin_port =htons (port); - srx->transport.sin.sin_addr.s_addr = xdr; + alist->addrs[i].peer = peer; alist->nr_ipv4++; alist->nr_addrs++; +return 0 ; }/* * Merge an IPv6 entry into a fileserver address list. */ -void afs_merge_fs_addr6 (struct afs_addr_list *alist,__be32 *xdr,u16 port) +int afs_merge_fs_addr6 (struct afs_net *net,struct afs_addr_list *alist, +__be32 *xdr,u16 port) { -struct sockaddr_rxrpc *srx; -int i, diff; +struct sockaddr_rxrpc srx; +struct rxrpc_peer *peer; +int i;if (alist->nr_addrs >= alist->max_addrs) -return ; +return 0 ; -for (i = alist->nr_ipv4; i < alist->nr_addrs; i++) { -struct sockaddr_in6 *a = &alist->addrs[i].srx.transport.sin6; -u16 a_port =ntohs (a->sin6_port); + srx.srx_family =AF_RXRPC ; + srx.transport_type =SOCK_DGRAM ; + srx.transport_len =sizeof (srx.transport.sin6); + srx.transport.sin6.sin6_family =AF_INET6 ; + srx.transport.sin6.sin6_port =htons (port); +memcpy (&srx.transport.sin6.sin6_addr, xdr,16 ); - diff =memcmp (xdr, &a->sin6_addr,16 ); -if (diff ==0 && port == a_port) -return ; -if (diff ==0 && port < a_port) -break ; -if (diff <0 ) + peer =rxrpc_kernel_lookup_peer (net->socket, &srx,GFP_KERNEL ); +if (!peer) +return -ENOMEM ; + +for (i = alist->nr_ipv4; i < alist->nr_addrs; i++) { +if (peer == alist->addrs[i].peer) { +rxrpc_kernel_put_peer (peer); +return 0 ; + } +if (peer <= alist->addrs[i].peer)break ; }
@@ -337,15 +350,9 @@ void afs_merge_fs_addr6(struct afs_addr_list *alist, __be32 *xdr, u16 port)memmove (alist->addrs + i +1 , alist->addrs + i,sizeof (alist->addrs[0 ]) * (alist->nr_addrs - i)); - - srx = &alist->addrs[i].srx; - srx->srx_family =AF_RXRPC ; - srx->transport_type =SOCK_DGRAM ; - srx->transport_len =sizeof (srx->transport.sin6); - srx->transport.sin6.sin6_family =AF_INET6 ; - srx->transport.sin6.sin6_port =htons (port); -memcpy (&srx->transport.sin6.sin6_addr, xdr,16 ); + alist->addrs[i].peer = peer; alist->nr_addrs++; +return 0 ; }/*
fs/afs/cmservice.c +3 -2
@@ -146,10 +146,11 @@ static int afs_find_cm_server_by_peer(struct afs_call *call) {struct sockaddr_rxrpc srx;struct afs_server *server; +struct rxrpc_peer *peer; -rxrpc_kernel_get_peer (call->net->socket, call->rxcall, &srx); + peer =rxrpc_kernel_get_call_peer (call->net->socket, call->rxcall); - server =afs_find_server (call->net, &srx); + server =afs_find_server (call->net, peer);if (!server) {trace_afs_cm_no_server (call, &srx);return 0 ;
fs/afs/fs_probe.c +6 -5
@@ -101,6 +101,7 @@ static void afs_fs_probe_not_done(struct afs_net *net,void afs_fileserver_probe_result (struct afs_call *call) {struct afs_addr_list *alist = call->alist; +struct afs_address *addr = &alist->addrs[call->addr_ix];struct afs_server *server = call->server;unsigned int index = call->addr_ix;unsigned int rtt_us =0 , cap0;
@@ -153,12 +154,12 @@ void afs_fileserver_probe_result(struct afs_call *call)if (call->service_id ==YFS_FS_SERVICE ) { server->probe.is_yfs = true;set_bit (AFS_SERVER_FL_IS_YFS , &server->flags); - alist->addrs[index].srx.srx_service = call->service_id; + addr->service_id = call->service_id; }else { server->probe.not_yfs = true;if (!server->probe.is_yfs) {clear_bit (AFS_SERVER_FL_IS_YFS , &server->flags); - alist->addrs[index].srx.srx_service = call->service_id; + addr->service_id = call->service_id; } cap0 =ntohl (call->tmp);if (cap0 &AFS3_VICED_CAPABILITY_64BITFILES )
@@ -167,7 +168,7 @@ void afs_fileserver_probe_result(struct afs_call *call)clear_bit (AFS_SERVER_FL_HAS_FS64 , &server->flags); } -rxrpc_kernel_get_srtt (call->net->socket, call->rxcall, &rtt_us); + rtt_us =rxrpc_kernel_get_srtt (addr->peer);if (rtt_us < server->probe.rtt) { server->probe.rtt = rtt_us; server->rtt = rtt_us;
@@ -181,8 +182,8 @@ void afs_fileserver_probe_result(struct afs_call *call) out:spin_unlock (&server->probe_lock); -_debug ("probe %pU [%u] %pISpc rtt=%u ret=%d" , - &server->uuid, index, &alist->addrs[index].srx.transport, +_debug ("probe %pU [%u] %pISpc rtt=%d ret=%d" , + &server->uuid, index,rxrpc_kernel_remote_addr (alist->addrs[index].peer), rtt_us, ret);return afs_done_one_fs_probe (call->net, server);
fs/afs/internal.h +14 -12
@@ -72,6 +72,11 @@ enum afs_call_state { AFS_CALL_COMPLETE, /* Completed or failed */ }; +struct afs_address { +struct rxrpc_peer *peer; +u16 service_id; +}; +/* * List of server addresses. */
@@ -87,9 +92,7 @@ struct afs_addr_list { enum dns_lookup_status status:8;unsigned long failed;/* Mask of addrs that failed locally/ICMP */ unsigned long responded;/* Mask of addrs that responded */ -struct { -struct sockaddr_rxrpc srx; - } addrs[] __counted_by(max_addrs); + struct afs_address addrs[] __counted_by(max_addrs);#define AFS_MAX_ADDRESSES ((unsigned int)(sizeof(unsigned long) * 8)) };
@@ -420,7 +423,7 @@ struct afs_vlserver {atomic_t probe_outstanding;spinlock_t probe_lock;struct { -unsigned int rtt;/* RTT in uS */ +unsigned int rtt;/* Best RTT in uS (or UINT_MAX) */ u32 abort_code;short error;unsigned short flags;
@@ -537,7 +540,7 @@ struct afs_server {atomic_t probe_outstanding;spinlock_t probe_lock;struct { -unsigned int rtt;/* RTT in uS */ +unsigned int rtt;/* Best RTT in uS (or UINT_MAX) */ u32 abort_code;short error;bool responded:1 ;
@@ -964,9 +967,7 @@ static inline struct afs_addr_list *afs_get_addrlist(struct afs_addr_list *alistrefcount_inc (&alist->usage);return alist; } -extern struct afs_addr_list *afs_alloc_addrlist (unsigned int , -unsigned short , -unsigned short ); +extern struct afs_addr_list *afs_alloc_addrlist (unsigned int nr,u16 service_id);extern void afs_put_addrlist (struct afs_addr_list *); extern struct afs_vlserver_list *afs_parse_text_addrs(struct afs_net *, const char *, size_t, char,
@@ -977,8 +978,10 @@ extern struct afs_vlserver_list *afs_dns_query(struct afs_cell *, time64_t *);extern bool afs_iterate_addresses (struct afs_addr_cursor *);extern int afs_end_cursor (struct afs_addr_cursor *); -extern void afs_merge_fs_addr4 (struct afs_addr_list *,__be32 ,u16 ); -extern void afs_merge_fs_addr6 (struct afs_addr_list *,__be32 *,u16 ); +extern int afs_merge_fs_addr4 (struct afs_net *net,struct afs_addr_list *addr, +__be32 xdr,u16 port); +extern int afs_merge_fs_addr6 (struct afs_net *net,struct afs_addr_list *addr, +__be32 *xdr,u16 port);/* * callback.c
@@ -1405,8 +1408,7 @@ extern void __exit afs_clean_up_permit_cache(void);*/ extern spinlock_t afs_server_peer_lock; -extern struct afs_server *afs_find_server (struct afs_net *, -const struct sockaddr_rxrpc *); +extern struct afs_server *afs_find_server (struct afs_net *,const struct rxrpc_peer *);extern struct afs_server *afs_find_server_by_uuid (struct afs_net *,const uuid_t *);extern struct afs_server *afs_lookup_server (struct afs_cell *,struct key *,const uuid_t *,u32 );extern struct afs_server *afs_get_server (struct afs_server *,enum afs_server_trace );
fs/afs/proc.c +5 -4
@@ -307,7 +307,7 @@ static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)for (i =0 ; i < alist->nr_addrs; i++)seq_printf (m," %c %pISpc\n" , alist->preferred == i ?'>' :'-' , - &alist->addrs[i].srx.transport); +rxrpc_kernel_remote_addr (alist->addrs[i].peer)); }seq_printf (m," info: fl=%lx rtt=%d\n" , vlserver->flags, vlserver->rtt); seq_printf(m, " probe: fl=%x e=%d ac=%d out=%d\n",
@@ -398,9 +398,10 @@ static int afs_proc_servers_show(struct seq_file *m, void *v)seq_printf (m," - ALIST v=%u rsp=%lx f=%lx\n" , alist->version, alist->responded, alist->failed);for (i =0 ; i < alist->nr_addrs; i++) -seq_printf (m," [%x] %pISpc%s\n" , - i, &alist->addrs[i].srx.transport, - alist->preferred == i ?"*" :"" ); +seq_printf (m," [%x] %pISpc%s rtt=%d\n" , + i,rxrpc_kernel_remote_addr (alist->addrs[i].peer), + alist->preferred == i ?"*" :"" , +rxrpc_kernel_get_srtt (alist->addrs[i].peer));return 0 ; }
fs/afs/rotate.c +3 -3
@@ -113,7 +113,7 @@ bool afs_select_fileserver(struct afs_operation *op)struct afs_server *server;struct afs_vnode *vnode = op->file[0 ].vnode;struct afs_error e; -u32 rtt; +unsigned int rtt;int error = op->ac.error, i; _enter("%lx[%d],%lx[%d],%d,%d",
@@ -420,7 +420,7 @@ bool afs_select_fileserver(struct afs_operation *op) } op->index =-1 ; - rtt =U32_MAX ; + rtt =UINT_MAX ;for (i =0 ; i < op->server_list->nr_servers; i++) {struct afs_server *s = op->server_list->servers[i].server;
@@ -488,7 +488,7 @@ bool afs_select_fileserver(struct afs_operation *op)_debug ("address [%u] %u/%u %pISp" , op->index, op->ac.index, op->ac.alist->nr_addrs, - &op->ac.alist->addrs[op->ac.index].srx.transport); +rxrpc_kernel_remote_addr (op->ac.alist->addrs[op->ac.index].peer));_leave (" = t" );return true;
fs/afs/rxrpc.c +6 -4
@@ -296,7 +296,8 @@ static void afs_notify_end_request_tx(struct sock *sock,*/ void afs_make_call (struct afs_addr_cursor *ac,struct afs_call *call,gfp_t gfp) { -struct sockaddr_rxrpc *srx = &ac->alist->addrs[ac->index].srx; +struct afs_address *addr = &ac->alist->addrs[ac->index]; +struct rxrpc_peer *peer = addr->peer;struct rxrpc_call *rxcall;struct msghdr msg;struct kvec iov[1 ];
@@ -304,7 +305,7 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp)s64 tx_total_len;int ret; -_enter (",{%pISp}," , &srx->transport); +_enter (",{%pISp}," ,rxrpc_kernel_remote_addr (addr->peer));ASSERT (call->type !=NULL );ASSERT (call->type->name !=NULL );
@@ -333,7 +334,7 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp) }/* create a call */ - rxcall = rxrpc_kernel_begin_call(call->net->socket, srx, call->key, + rxcall = rxrpc_kernel_begin_call(call->net->socket, peer, call->key, (unsigned long)call, tx_total_len, call->max_lifespan,
@@ -341,6 +342,7 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp) (call->async ? afs_wake_up_async_call : afs_wake_up_call_waiter), + addr->service_id, call->upgrade, (call->intr ?RXRPC_PREINTERRUPTIBLE : RXRPC_UNINTERRUPTIBLE),
@@ -461,7 +463,7 @@ static void afs_log_error(struct afs_call *call, s32 remote_abort) max = m +1 ;pr_notice ("kAFS: Peer reported %s failure on %s [%pISp]\n" , msg, call->type->name, - &call->alist->addrs[call->addr_ix].srx.transport); +rxrpc_kernel_remote_addr (call->alist->addrs[call->addr_ix].peer)); } }
fs/afs/server.c +7 -34
57 lines not on this page · raw message
fs/afs/vl_alias.c +3 -52
67 lines not on this page · raw message
fs/afs/vl_list.c +10 -5
@@ -83,14 +83,15 @@ static u16 afs_extract_le16(const u8 **_b)/* * Build a VL server address list from a DNS queried server list. */ -static struct afs_addr_list *afs_extract_vl_addrs (const u8 **_b,const u8 *end, +static struct afs_addr_list *afs_extract_vl_addrs (struct afs_net *net, +const u8 **_b,const u8 *end,u8 nr_addrs,u16 port) {struct afs_addr_list *alist;const u8 *b = *_b;int ret = -EINVAL ; - alist =afs_alloc_addrlist (nr_addrs,VL_SERVICE , port); + alist =afs_alloc_addrlist (nr_addrs,VL_SERVICE );if (!alist)return ERR_PTR (-ENOMEM );if (nr_addrs ==0 )
@@ -109,7 +110,9 @@ static struct afs_addr_list *afs_extract_vl_addrs(const u8 **_b, const u8 *end, goto error; }memcpy (x, b,4 ); -afs_merge_fs_addr4 (alist, x[0 ], port); + ret =afs_merge_fs_addr4 (net, alist, x[0 ], port); +if (ret <0 ) + goto error; b +=4 ;break ;
@@ -119,7 +122,9 @@ static struct afs_addr_list *afs_extract_vl_addrs(const u8 **_b, const u8 *end, goto error; }memcpy (x, b,16 ); -afs_merge_fs_addr6 (alist, x, port); + ret =afs_merge_fs_addr6 (net, alist, x, port); +if (ret <0 ) + goto error; b +=16 ;break ;
@@ -247,7 +252,7 @@ struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *cell,/* Extract the addresses - note that we can't skip this as we * have to advance the payload pointer. */ - addrs =afs_extract_vl_addrs (&b, end, bs.nr_addrs, bs.port); + addrs =afs_extract_vl_addrs (cell->net, &b, end, bs.nr_addrs, bs.port);if (IS_ERR (addrs)) { ret =PTR_ERR (addrs); goto error_2;
fs/afs/vl_probe.c +7 -5
@@ -48,6 +48,7 @@ void afs_vlserver_probe_result(struct afs_call *call) {struct afs_addr_list *alist = call->alist;struct afs_vlserver *server = call->vlserver; +struct afs_address *addr = &alist->addrs[call->addr_ix];unsigned int server_index = call->server_index;unsigned int rtt_us =0 ;unsigned int index = call->addr_ix;
@@ -106,16 +107,16 @@ void afs_vlserver_probe_result(struct afs_call *call)if (call->service_id ==YFS_VL_SERVICE ) { server->probe.flags |=AFS_VLSERVER_PROBE_IS_YFS ;set_bit (AFS_VLSERVER_FL_IS_YFS , &server->flags); - alist->addrs[index].srx.srx_service = call->service_id; + addr->service_id = call->service_id; }else { server->probe.flags |=AFS_VLSERVER_PROBE_NOT_YFS ;if (!(server->probe.flags &AFS_VLSERVER_PROBE_IS_YFS )) {clear_bit (AFS_VLSERVER_FL_IS_YFS , &server->flags); - alist->addrs[index].srx.srx_service = call->service_id; + addr->service_id = call->service_id; } } -rxrpc_kernel_get_srtt (call->net->socket, call->rxcall, &rtt_us); + rtt_us =rxrpc_kernel_get_srtt (addr->peer);if (rtt_us < server->probe.rtt) { server->probe.rtt = rtt_us; server->rtt = rtt_us;
@@ -130,8 +131,9 @@ void afs_vlserver_probe_result(struct afs_call *call) out:spin_unlock (&server->probe_lock); -_debug ("probe [%u][%u] %pISpc rtt=%u ret=%d" , - server_index, index, &alist->addrs[index].srx.transport, rtt_us, ret); +_debug ("probe [%u][%u] %pISpc rtt=%d ret=%d" , + server_index, index,rxrpc_kernel_remote_addr (addr->peer), + rtt_us, ret);afs_done_one_vl_probe (server, have_result); }
fs/afs/vl_rotate.c +3 -3
@@ -92,7 +92,7 @@ bool afs_select_vlserver(struct afs_vl_cursor *vc)struct afs_addr_list *alist;struct afs_vlserver *vlserver;struct afs_error e; -u32 rtt; +unsigned int rtt;int error = vc->ac.error, i; _enter("%lx[%d],%lx[%d],%d,%d",
@@ -194,7 +194,7 @@ bool afs_select_vlserver(struct afs_vl_cursor *vc) goto selected_server; vc->index =-1 ; - rtt =U32_MAX ; + rtt =UINT_MAX ;for (i =0 ; i < vc->server_list->nr_servers; i++) {struct afs_vlserver *s = vc->server_list->servers[i].server;
@@ -249,7 +249,7 @@ bool afs_select_vlserver(struct afs_vl_cursor *vc)_debug ("VL address %d/%d" , vc->ac.index, vc->ac.alist->nr_addrs); -_leave (" = t %pISpc" , &vc->ac.alist->addrs[vc->ac.index].srx.transport); +_leave (" = t %pISpc" ,rxrpc_kernel_remote_addr (vc->ac.alist->addrs[vc->ac.index].peer));return true; next_server:
fs/afs/vlclient.c +15 -7
@@ -208,7 +208,7 @@ static int afs_deliver_vl_get_addrs_u(struct afs_call *call) count =ntohl (*bp); nentries =min (nentries, count); - alist =afs_alloc_addrlist (nentries,FS_SERVICE ,AFS_FS_PORT ); + alist =afs_alloc_addrlist (nentries,FS_SERVICE );if (!alist)return -ENOMEM ; alist->version = uniquifier;
@@ -230,9 +230,13 @@ static int afs_deliver_vl_get_addrs_u(struct afs_call *call) alist = call->ret_alist; bp = call->buffer; count =min (call->count,4U ); -for (i =0 ; i < count; i++) -if (alist->nr_addrs < call->count2) -afs_merge_fs_addr4 (alist, *bp++,AFS_FS_PORT ); +for (i =0 ; i < count; i++) { +if (alist->nr_addrs < call->count2) { + ret =afs_merge_fs_addr4 (call->net, alist, *bp++,AFS_FS_PORT ); +if (ret <0 ) +return ret; + } + } call->count -= count;if (call->count >0 )
@@ -450,7 +454,7 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)if (call->count >YFS_MAXENDPOINTS )return afs_protocol_error (call, afs_eproto_yvl_fsendpt_num); - alist =afs_alloc_addrlist (call->count,FS_SERVICE ,AFS_FS_PORT ); + alist =afs_alloc_addrlist (call->count,FS_SERVICE );if (!alist)return -ENOMEM ; alist->version = uniquifier;
@@ -488,14 +492,18 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)if (ntohl (bp[0 ]) !=sizeof (__be32) *2 )return afs_protocol_error ( call, afs_eproto_yvl_fsendpt4_len); -afs_merge_fs_addr4 (alist, bp[1 ],ntohl (bp[2 ])); + ret =afs_merge_fs_addr4 (call->net, alist, bp[1 ],ntohl (bp[2 ])); +if (ret <0 ) +return ret; bp +=3 ;break ;case YFS_ENDPOINT_IPV6 :if (ntohl (bp[0 ]) !=sizeof (__be32) *5 )return afs_protocol_error ( call, afs_eproto_yvl_fsendpt6_len); -afs_merge_fs_addr6 (alist, bp +1 ,ntohl (bp[5 ])); + ret =afs_merge_fs_addr6 (call->net, alist, bp +1 ,ntohl (bp[5 ])); +if (ret <0 ) +return ret; bp +=6 ;break ;default :
include/net/af_rxrpc.h +11 -4
@@ -15,6 +15,7 @@ struct key;struct sock ;struct socket ;struct rxrpc_call ; +struct rxrpc_peer ;enum rxrpc_abort_reason ;enum rxrpc_interruptibility {
@@ -41,13 +42,14 @@ void rxrpc_kernel_new_call_notification(struct socket *, rxrpc_notify_new_call_t, rxrpc_discard_new_call_t);struct rxrpc_call *rxrpc_kernel_begin_call (struct socket *sock, -struct sockaddr_rxrpc *srx, +struct rxrpc_peer *peer,struct key *key,unsigned long user_call_ID,s64 tx_total_len,u32 hard_timeout,gfp_t gfp,rxrpc_notify_rx_t notify_rx, +u16 service_id,bool upgrade,enum rxrpc_interruptibility interruptibility,unsigned int debug_id);
@@ -60,9 +62,14 @@ bool rxrpc_kernel_abort_call(struct socket *, struct rxrpc_call *, u32, int, enum rxrpc_abort_reason);void rxrpc_kernel_shutdown_call (struct socket *sock,struct rxrpc_call *call);void rxrpc_kernel_put_call (struct socket *sock,struct rxrpc_call *call); -void rxrpc_kernel_get_peer (struct socket *,struct rxrpc_call *, -struct sockaddr_rxrpc *); -bool rxrpc_kernel_get_srtt (struct socket *,struct rxrpc_call *,u32 *); +struct rxrpc_peer *rxrpc_kernel_lookup_peer (struct socket *sock, +struct sockaddr_rxrpc *srx,gfp_t gfp); +void rxrpc_kernel_put_peer (struct rxrpc_peer *peer); +struct rxrpc_peer *rxrpc_kernel_get_peer (struct rxrpc_peer *peer); +struct rxrpc_peer *rxrpc_kernel_get_call_peer (struct socket *sock,struct rxrpc_call *call); +const struct sockaddr_rxrpc *rxrpc_kernel_remote_srx (const struct rxrpc_peer *peer); +const struct sockaddr *rxrpc_kernel_remote_addr (const struct rxrpc_peer *peer); +unsigned int rxrpc_kernel_get_srtt (const struct rxrpc_peer *);int rxrpc_kernel_charge_accept (struct socket *,rxrpc_notify_rx_t ,rxrpc_user_attach_call_t ,unsigned long ,gfp_t ,unsigned int );
include/trace/events/rxrpc.h +3 -0
@@ -178,7 +178,9 @@#define rxrpc_peer_traces \ EM(rxrpc_peer_free, "FREE ") \ EM(rxrpc_peer_get_accept, "GET accept ") \ + EM(rxrpc_peer_get_application, "GET app ") \ EM(rxrpc_peer_get_bundle, "GET bundle ") \ + EM(rxrpc_peer_get_call, "GET call ") \ EM(rxrpc_peer_get_client_conn, "GET cln-conn") \ EM(rxrpc_peer_get_input, "GET input ") \ EM(rxrpc_peer_get_input_error, "GET inpt-err") \
@@ -187,6 +189,7 @@ EM(rxrpc_peer_get_service_conn, "GET srv-conn") \ EM(rxrpc_peer_new_client, "NEW client ") \ EM(rxrpc_peer_new_prealloc, "NEW prealloc") \ + EM(rxrpc_peer_put_application, "PUT app ") \ EM(rxrpc_peer_put_bundle, "PUT bundle ") \ EM(rxrpc_peer_put_call, "PUT call ") \EM (rxrpc_peer_put_conn,"PUT conn " ) \
net/rxrpc/af_rxrpc.c +54 -8
108 lines not on this page · raw message
net/rxrpc/ar-internal.h +1 -1
@@ -364,6 +364,7 @@ struct rxrpc_conn_proto {struct rxrpc_conn_parameters {struct rxrpc_local *local;/* Representation of local endpoint */ +struct rxrpc_peer *peer;/* Representation of remote endpoint */ struct key *key;/* Security details */ bool exclusive;/* T if conn is exclusive */ bool upgrade;/* T if service ID can be upgraded */
@@ -867,7 +868,6 @@ struct rxrpc_call *rxrpc_find_call_by_user_ID(struct rxrpc_sock *, unsigned longstruct rxrpc_call *rxrpc_alloc_call (struct rxrpc_sock *,gfp_t ,unsigned int );struct rxrpc_call *rxrpc_new_client_call (struct rxrpc_sock *,struct rxrpc_conn_parameters *, -struct sockaddr_rxrpc *,struct rxrpc_call_params *,gfp_t ,unsigned int );void rxrpc_start_call_timer (struct rxrpc_call *call);
net/rxrpc/call_object.c +9 -8
@@ -193,7 +193,6 @@ struct rxrpc_call *rxrpc_alloc_call(struct rxrpc_sock *rx, gfp_t gfp,* Allocate a new client call. */ static struct rxrpc_call *rxrpc_alloc_client_call(struct rxrpc_sock *rx, - struct sockaddr_rxrpc *srx, struct rxrpc_conn_parameters *cp, struct rxrpc_call_params *p, gfp_t gfp,
@@ -211,10 +210,12 @@ static struct rxrpc_call *rxrpc_alloc_client_call(struct rxrpc_sock *rx, now =ktime_get_real (); call->acks_latest_ts = now; call->cong_tstamp = now; - call->dest_srx = *srx; + call->dest_srx = cp->peer->srx; + call->dest_srx.srx_service = cp->service_id; call->interruptibility = p->interruptibility; call->tx_total_len = p->tx_total_len; call->key =key_get (cp->key); + call->peer =rxrpc_get_peer (cp->peer, rxrpc_peer_get_call); call->local =rxrpc_get_local (cp->local, rxrpc_local_get_call); call->security_level = cp->security_level;if (p->kernel)
@@ -306,10 +307,6 @@ static int rxrpc_connect_call(struct rxrpc_call *call, gfp_t gfp)_enter ("{%d,%lx}," , call->debug_id, call->user_call_ID); - call->peer =rxrpc_lookup_peer (local, &call->dest_srx, gfp); -if (!call->peer) - goto error; - ret =rxrpc_look_up_bundle (call, gfp);if (ret <0 ) goto error;
@@ -334,7 +331,6 @@ static int rxrpc_connect_call(struct rxrpc_call *call, gfp_t gfp)*/ struct rxrpc_call *rxrpc_new_client_call (struct rxrpc_sock *rx,struct rxrpc_conn_parameters *cp, -struct sockaddr_rxrpc *srx,struct rxrpc_call_params *p,gfp_t gfp,unsigned int debug_id)
@@ -349,13 +345,18 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,_enter ("%p,%lx" , rx, p->user_call_ID); +if (WARN_ON_ONCE (!cp->peer)) { +release_sock (&rx->sk); +return ERR_PTR (-EIO ); + } + limiter =rxrpc_get_call_slot (p, gfp);if (!limiter) {release_sock (&rx->sk);return ERR_PTR (-ERESTARTSYS ); } - call =rxrpc_alloc_client_call (rx, srx, cp, p, gfp, debug_id); + call =rxrpc_alloc_client_call (rx, cp, p, gfp, debug_id);if (IS_ERR (call)) {release_sock (&rx->sk);up (limiter);
net/rxrpc/peer_object.c +37 -21
82 lines not on this page · raw message
net/rxrpc/sendmsg.c +10 -1
@@ -572,6 +572,7 @@ rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, __acquires(&call->user_mutex) {struct rxrpc_conn_parameters cp; +struct rxrpc_peer *peer;struct rxrpc_call *call;struct key *key;
@@ -584,21 +585,29 @@ rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg,return ERR_PTR (-EDESTADDRREQ ); } + peer =rxrpc_lookup_peer (rx->local, srx,GFP_KERNEL ); +if (!peer) { +release_sock (&rx->sk); +return ERR_PTR (-ENOMEM ); + } + key = rx->key;if (key && !rx->key->payload.data[0 ]) key =NULL ;memset (&cp,0 ,sizeof (cp)); cp.local = rx->local; + cp.peer = peer; cp.key = rx->key; cp.security_level = rx->min_sec_level; cp.exclusive = rx->exclusive | p->exclusive; cp.upgrade = p->upgrade; cp.service_id = srx->srx_service; - call =rxrpc_new_client_call (rx, &cp, srx, &p->call,GFP_KERNEL , + call =rxrpc_new_client_call (rx, &cp, &p->call,GFP_KERNEL ,atomic_inc_return (&rxrpc_debug_id));/* The socket is now unlocked */ +rxrpc_put_peer (peer, rxrpc_peer_put_application);_leave (" = %p\n" , call);return call; }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 174/346 afs: Handle the VIO and UAEIO aborts explicitly
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
[ Upstream commit eb8eae65f0c713bcef84b082aa919f72c3d83268 ]
When processing the result of a call, handle the VIO and UAEIO abort specifically rather than leaving it to a default case. Rather than erroring out unconditionally, see if there's another server if the volume has more than one server available, otherwise return -EREMOTEIO.
Stable-dep-of: 17ba6f0bd14f ("afs: Fix error handling with lookup via FS.InlineBulkStatus")
--- fs/afs/rotate.c | 7 +++++++ 1 file changed, 7 insertions(+)
fs/afs/rotate.c +7 -0
@@ -330,6 +330,13 @@ bool afs_select_fileserver(struct afs_operation *op) goto restart_from_beginning; +case UAEIO : +case VIO : + op->error = -EREMOTEIO ; +if (op->volume->type !=AFSVL_RWVOL ) + goto next_server; + goto failed; +case VDISKFULL :case UAENOSPC :/* The partition is full. Only applies to RWVOLs.
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 175/346 afs: Use op->nr_iterations=-1 to indicate to begin fileserver iteration
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
[ Upstream commit 075171fd22be33acf4ab354814bfa6de1c3412ce ]
Set op->nr_iterations to -1 to indicate that we need to begin fileserver iteration rather than setting error to SHRT_MAX. This makes it easier to eliminate the address cursor.
Stable-dep-of: 17ba6f0bd14f ("afs: Fix error handling with lookup via FS.InlineBulkStatus")
--- fs/afs/fs_operation.c | 2 +- fs/afs/internal.h | 2 +- fs/afs/rotate.c | 11 ++++++----- 3 files changed, 8 insertions(+), 7 deletions(-)
fs/afs/fs_operation.c +1 -1
@@ -41,7 +41,7 @@ struct afs_operation *afs_alloc_operation(struct key *key, struct afs_volume *vo op->cb_v_break = volume->cb_v_break; op->debug_id =atomic_inc_return (&afs_operation_debug_counter); op->error = -EDESTADDRREQ ; - op->ac.error =SHRT_MAX ; + op->nr_iterations =-1 ;_leave (" = [op=%08x]" , op->debug_id);return op;
fs/afs/internal.h +1 -1
@@ -859,7 +859,7 @@ struct afs_operation {struct afs_call *call;unsigned long untried;/* Bitmask of untried servers */ short index;/* Current server */ -unsigned short nr_iterations;/* Number of server iterations */ +short nr_iterations;/* Number of server iterations */ unsigned int flags;#define AFS_OPERATION_STOP 0x0001/* Set to cease iteration */
fs/afs/rotate.c +6 -5
@@ -116,7 +116,10 @@ bool afs_select_fileserver(struct afs_operation *op)unsigned int rtt;int error = op->ac.error, i; -_enter ("%lx[%d],%lx[%d],%d,%d" , + op->nr_iterations++; + +_enter ("OP=%x+%x,%llx,%lx[%d],%lx[%d],%d,%d" , + op->debug_id, op->nr_iterations, op->volume->vid, op->untried, op->index, op->ac.tried, op->ac.index, error, op->ac.abort_code);
@@ -126,13 +129,11 @@ bool afs_select_fileserver(struct afs_operation *op)return false; } - op->nr_iterations++; +if (op->nr_iterations ==0 ) + goto start;/* Evaluate the result of the previous operation, if there was one. */ switch (error) { -case SHRT_MAX : - goto start; -case 0 :default :/* Success or local failure. Stop. */
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 176/346 afs: Wrap most op->error accesses with inline funcs
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
[ Upstream commit 2de5599f63babb416e09b1a6be429a47910dd47c ]
Wrap most op->error accesses with inline funcs which will make it easier for a subsequent patch to replace op->error with something else. Two functions are added to this end:
(1) afs_op_error() - Get the error code.
(2) afs_op_set_error() - Set the error code.
Stable-dep-of: 17ba6f0bd14f ("afs: Fix error handling with lookup via FS.InlineBulkStatus")
--- fs/afs/dir.c | 38 +++++++++++++++--------------- fs/afs/file.c | 4 ++-- fs/afs/fs_operation.c | 21 ++++++++++------- fs/afs/fsclient.c | 2 +- fs/afs/inode.c | 2 +- fs/afs/internal.h | 20 ++++++++++++---- fs/afs/rotate.c | 55 ++++++++++++++++++++++++------------------- fs/afs/server.c | 6 ++--- fs/afs/write.c | 6 ++--- 9 files changed, 87 insertions(+), 67 deletions(-)
fs/afs/dir.c +19 -19
@@ -886,14 +886,14 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,* lookups contained therein are stored in the reply without aborting * the whole operation. */ - op->error = -ENOTSUPP ; +afs_op_set_error (op, -ENOTSUPP );if (!cookie->one_only) { op->ops = &afs_inline_bulk_status_operation;afs_begin_vnode_operation (op);afs_wait_for_operation (op); } -if (op->error == -ENOTSUPP ) { +if (afs_op_error (op) == -ENOTSUPP ) {/* We could try FS.BulkStatus next, but this aborts the entire * op if any of the lookups fails - so, for the moment, revert * to FS.FetchStatus for op->file[1].
@@ -903,10 +903,10 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,afs_begin_vnode_operation (op);afs_wait_for_operation (op); } - inode =ERR_PTR (op->error); + inode =ERR_PTR (afs_op_error (op)); out_op: -if (op->error ==0 ) { +if (!afs_op_error (op)) { inode = &op->file[1 ].vnode->netfs.inode; op->file[1 ].vnode =NULL ; }
@@ -1281,7 +1281,7 @@ static void afs_vnode_new_inode(struct afs_operation *op)_enter ("" ); - ASSERTCMP(op->error, ==, 0); + ASSERTCMP(afs_op_error(op), ==, 0); inode =afs_iget (op, vp);if (IS_ERR (inode)) {
@@ -1294,7 +1294,7 @@ static void afs_vnode_new_inode(struct afs_operation *op) vnode =AFS_FS_I (inode);set_bit (AFS_VNODE_NEW_CONTENT , &vnode->flags); -if (!op->error) +if (!afs_op_error (op))afs_cache_permit (vnode, op->key, vnode->cb_break, &vp->scb);d_instantiate (op->dentry, inode); }
@@ -1328,7 +1328,7 @@ static void afs_create_put(struct afs_operation *op) {_enter ("op=%08x" , op->debug_id); -if (op->error) +if (afs_op_error (op))d_drop (op->dentry); }
@@ -1488,7 +1488,7 @@ static void afs_dir_remove_link(struct afs_operation *op)struct dentry *dentry = op->dentry;int ret; -if (op->error !=0 || +if (afs_op_error (op) || (op->file[1 ].scb.have_status && op->file[1 ].scb.have_error))return ;if (d_really_is_positive (dentry))
@@ -1512,10 +1512,10 @@ static void afs_dir_remove_link(struct afs_operation *op) ret =afs_validate (vnode, op->key);if (ret != -ESTALE ) - op->error = ret; +afs_op_set_error (op, ret); } -_debug ("nlink %d [val %d]" , vnode->netfs.inode.i_nlink, op->error); +_debug ("nlink %d [val %d]" , vnode->netfs.inode.i_nlink,afs_op_error (op)); }static void afs_unlink_success (struct afs_operation *op)
@@ -1546,7 +1546,7 @@ static void afs_unlink_edit_dir(struct afs_operation *op)static void afs_unlink_put (struct afs_operation *op) {_enter ("op=%08x" , op->debug_id); -if (op->unlink.need_rehash && op->error <0 && op->error != -ENOENT ) +if (op->unlink.need_rehash &&afs_op_error (op) <0 &&afs_op_error (op) != -ENOENT )d_rehash (op->dentry); }
@@ -1587,7 +1587,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)/* Try to make sure we have a callback promise on the victim. */ ret =afs_validate (vnode, op->key);if (ret <0 ) { - op->error = ret; +afs_op_set_error (op, ret); goto error; }
@@ -1596,7 +1596,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)spin_unlock (&dentry->d_lock);/* Start asynchronous writeout of the inode */ write_inode_now (d_inode (dentry),0 ); - op->error =afs_sillyrename (dvnode, vnode, dentry, op->key); +afs_op_set_error (op,afs_sillyrename (dvnode, vnode, dentry, op->key)); goto error; }if (!d_unhashed (dentry)) {
@@ -1617,7 +1617,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)/* If there was a conflict with a third party, check the status of the * unlinked vnode. */ -if (op->error ==0 && (op->flags &AFS_OPERATION_DIR_CONFLICT )) { +if (afs_op_error (op) ==0 && (op->flags &AFS_OPERATION_DIR_CONFLICT )) { op->file[1 ].update_ctime = false; op->fetch_status.which =1 ; op->ops = &afs_fetch_status_operation;
@@ -1699,7 +1699,7 @@ static void afs_link_success(struct afs_operation *op)static void afs_link_put (struct afs_operation *op) {_enter ("op=%08x" , op->debug_id); -if (op->error) +if (afs_op_error (op))d_drop (op->dentry); }
@@ -1897,7 +1897,7 @@ static void afs_rename_put(struct afs_operation *op)if (op->rename.rehash)d_rehash (op->rename.rehash);dput (op->rename.tmp); -if (op->error) +if (afs_op_error (op))d_rehash (op->dentry); }
@@ -1942,7 +1942,7 @@ static int afs_rename(struct mnt_idmap *idmap, struct inode *old_dir,return PTR_ERR (op); ret =afs_validate (vnode, op->key); - op->error = ret; +afs_op_set_error (op, ret);if (ret <0 ) goto error;
@@ -1979,7 +1979,7 @@ static int afs_rename(struct mnt_idmap *idmap, struct inode *old_dir, op->rename.tmp =d_alloc (new_dentry->d_parent, &new_dentry->d_name);if (!op->rename.tmp) { - op->error = -ENOMEM ; +afs_op_nomem (op); goto error; }
@@ -1987,7 +1987,7 @@ static int afs_rename(struct mnt_idmap *idmap, struct inode *old_dir,AFS_FS_I (d_inode (new_dentry)), new_dentry, op->key);if (ret) { - op->error = ret; +afs_op_set_error (op, ret); goto error; }
fs/afs/file.c +2 -2
@@ -243,7 +243,7 @@ static void afs_fetch_data_notify(struct afs_operation *op) {struct afs_read *req = op->fetch.req;struct netfs_io_subrequest *subreq = req->subreq; -int error = op->error; +int error =afs_op_error (op);if (error == -ECONNABORTED ) error =afs_abort_to_error (op->ac.abort_code);
@@ -271,7 +271,7 @@ static void afs_fetch_data_success(struct afs_operation *op)static void afs_fetch_data_put (struct afs_operation *op) { - op->fetch.req->error = op->error; + op->fetch.req->error =afs_op_error (op);afs_put_read (op->fetch.req); }
fs/afs/fs_operation.c +12 -9
@@ -40,8 +40,8 @@ struct afs_operation *afs_alloc_operation(struct key *key, struct afs_volume *vo op->net = volume->cell->net; op->cb_v_break = volume->cb_v_break; op->debug_id =atomic_inc_return (&afs_operation_debug_counter); - op->error = -EDESTADDRREQ ; op->nr_iterations =-1 ; +afs_op_set_error (op, -EDESTADDRREQ );_leave (" = [op=%08x]" , op->debug_id);return op;
@@ -71,7 +71,7 @@ static bool afs_get_io_locks(struct afs_operation *op)swap (vnode, vnode2);if (mutex_lock_interruptible (&vnode->io_lock) <0 ) { - op->error = -ERESTARTSYS ; +afs_op_set_error (op, -ERESTARTSYS ); op->flags |=AFS_OPERATION_STOP ;_leave (" = f [I 0]" );return false;
@@ -80,7 +80,7 @@ static bool afs_get_io_locks(struct afs_operation *op)if (vnode2) {if (mutex_lock_interruptible_nested (&vnode2->io_lock,1 ) <0 ) { - op->error = -ERESTARTSYS ; +afs_op_set_error (op, -ERESTARTSYS ); op->flags |=AFS_OPERATION_STOP ;mutex_unlock (&vnode->io_lock); op->flags &= ~AFS_OPERATION_LOCK_0 ;
@@ -159,11 +159,14 @@ static void afs_end_vnode_operation(struct afs_operation *op) {_enter ("" ); -if (op->error == -EDESTADDRREQ || - op->error == -EADDRNOTAVAIL || - op->error == -ENETUNREACH || - op->error == -EHOSTUNREACH ) +switch (afs_op_error (op)) { +case -EDESTADDRREQ : +case -EADDRNOTAVAIL : +case -ENETUNREACH : +case -EHOSTUNREACH :afs_dump_edestaddrreq (op); +break ; + }afs_drop_io_locks (op);
@@ -209,7 +212,7 @@ void afs_wait_for_operation(struct afs_operation *op)afs_end_vnode_operation (op); -if (op->error ==0 && op->ops->edit_dir) { +if (!afs_op_error (op) && op->ops->edit_dir) {_debug ("edit_dir" ); op->ops->edit_dir (op); }
@@ -221,7 +224,7 @@ void afs_wait_for_operation(struct afs_operation *op)*/ int afs_put_operation (struct afs_operation *op) { -int i, ret = op->error; +int i, ret =afs_op_error (op);_enter ("op=%08x,%d" , op->debug_id, ret);
fs/afs/fsclient.c +1 -1
@@ -1899,7 +1899,7 @@ void afs_fs_inline_bulk_status(struct afs_operation *op)int i;if (test_bit (AFS_SERVER_FL_NO_IBULK , &op->server->flags)) { - op->error = -ENOTSUPP ; +afs_op_set_error (op, -ENOTSUPP );return ; }
fs/afs/inode.c +1 -1
@@ -331,7 +331,7 @@ static void afs_fetch_status_success(struct afs_operation *op)if (vnode->netfs.inode.i_state &I_NEW ) { ret =afs_inode_init_from_status (op, vp, vnode); - op->error = ret; +afs_op_set_error (op, ret);if (ret ==0 )afs_cache_permit (vnode, op->key, vp->cb_break_before, &vp->scb); }else {
fs/afs/internal.h +15 -5
@@ -1140,11 +1140,6 @@ extern bool afs_begin_vnode_operation(struct afs_operation *);extern void afs_wait_for_operation (struct afs_operation *);extern int afs_do_sync_operation (struct afs_operation *); -static inline void afs_op_nomem (struct afs_operation *op) -{ - op->error = -ENOMEM ; -} -static inline void afs_op_set_vnode (struct afs_operation *op,unsigned int n,struct afs_vnode *vnode) {
@@ -1238,6 +1233,21 @@ static inline void __afs_stat(atomic_t *s)extern int afs_abort_to_error (u32 );extern void afs_prioritise_error (struct afs_error *,int ,u32 ); +static inline void afs_op_nomem (struct afs_operation *op) +{ + op->error = -ENOMEM ; +} + +static inline int afs_op_error (const struct afs_operation *op) +{ +return op->error; +} + +static inline int afs_op_set_error (struct afs_operation *op,int error) +{ +return op->error = error; +} +/* * mntpt.c */
fs/afs/rotate.c +31 -24
160 lines not on this page · raw message
fs/afs/server.c +3 -3
@@ -629,8 +629,8 @@ static noinline bool afs_update_server_record(struct afs_operation *op,_leave (" = t [intr]" );return true; } - op->error =PTR_ERR (alist); -_leave (" = f [%d]" , op->error); +afs_op_set_error (op,PTR_ERR (alist)); +_leave (" = f [%d]" ,afs_op_error (op));return false; }
@@ -684,7 +684,7 @@ bool afs_check_server_record(struct afs_operation *op, struct afs_server *server (op->flags &AFS_OPERATION_UNINTR ) ? TASK_UNINTERRUPTIBLE : TASK_INTERRUPTIBLE);if (ret == -ERESTARTSYS ) { - op->error = ret; +afs_op_set_error (op, ret);_leave (" = f [intr]" );return false; }
fs/afs/write.c +3 -3
@@ -366,7 +366,7 @@ static void afs_store_data_success(struct afs_operation *op) op->ctime = op->file[0 ].scb.status.mtime_client;afs_vnode_commit_status (op, &op->file[0 ]); -if (op->error ==0 ) { +if (!afs_op_error (op)) {if (!op->store.laundering)afs_pages_written_back (vnode, op->store.pos, op->store.size);afs_stat_v (vnode, n_stores);
@@ -428,7 +428,7 @@ static int afs_store_data(struct afs_vnode *vnode, struct iov_iter *iter, loff_tafs_wait_for_operation (op); -switch (op->error) { +switch (afs_op_error (op)) {case -EACCES :case -EPERM :case -ENOKEY :
@@ -447,7 +447,7 @@ static int afs_store_data(struct afs_vnode *vnode, struct iov_iter *iter, loff_t }afs_put_wb_key (wbk); -_leave (" = %d" , op->error); +_leave (" = %d" ,afs_op_error (op));return afs_put_operation (op); }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 177/346 afs: Dont put afs_call in afs_wait_for_call_to_complete()
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
[ Upstream commit 6f2ff7e89bd05677f4c08fccafcf625ca3e09c1c ]
Don't put the afs_call struct in afs_wait_for_call_to_complete() but rather have the caller do it. This will allow the caller to fish stuff out of the afs_call struct rather than the afs_addr_cursor struct, thereby allowing a subsequent patch to subsume it.
Stable-dep-of: 17ba6f0bd14f ("afs: Fix error handling with lookup via FS.InlineBulkStatus")
--- fs/afs/fs_operation.c | 7 +++-- fs/afs/fsclient.c | 5 ++- fs/afs/internal.h | 2 +- fs/afs/rxrpc.c | 73 ++++++++++++++++--------------------------- fs/afs/vlclient.c | 64 ++++++++++++++++++++++--------------- 5 files changed, 75 insertions(+), 76 deletions(-)
fs/afs/fs_operation.c +5 -2
@@ -191,8 +191,11 @@ void afs_wait_for_operation(struct afs_operation *op)else op->ac.error = -ENOTSUPP ; -if (op->call) - op->error =afs_wait_for_call_to_complete (op->call, &op->ac); +if (op->call) { +afs_wait_for_call_to_complete (op->call, &op->ac); + op->error = op->ac.error; +afs_put_call (op->call); + } }switch (op->error) {
fs/afs/fsclient.c +4 -1
@@ -1612,6 +1612,7 @@ int afs_fs_give_up_all_callbacks(struct afs_net *net, {struct afs_call *call;__be32 *bp; +int ret;_enter ("" );
@@ -1627,7 +1628,9 @@ int afs_fs_give_up_all_callbacks(struct afs_net *net, call->server =afs_use_server (server, afs_server_trace_give_up_cb);afs_make_call (ac, call,GFP_NOFS ); -return afs_wait_for_call_to_complete (call, ac); +afs_wait_for_call_to_complete (call, ac); +afs_put_call (call); +return ret; }/*
fs/afs/internal.h +1 -1
@@ -1291,7 +1291,7 @@ extern void __net_exit afs_close_socket(struct afs_net *);extern void afs_charge_preallocation (struct work_struct *);extern void afs_put_call (struct afs_call *);extern void afs_make_call (struct afs_addr_cursor *,struct afs_call *,gfp_t ); -extern long afs_wait_for_call_to_complete (struct afs_call *,struct afs_addr_cursor *); +void afs_wait_for_call_to_complete (struct afs_call *call,struct afs_addr_cursor *ac);extern struct afs_call *afs_alloc_flat_call (struct afs_net *,const struct afs_call_type *,size_t ,size_t );
fs/afs/rxrpc.c +27 -46
98 lines not on this page · raw message
fs/afs/vlclient.c +38 -26
146 lines not on this page · raw message
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 178/346 afs: Simplify error handling
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
[ Upstream commit aa453becce5d1ae1b94b7fc22f47d7b05d22b14e ]
Simplify error handling a bit by moving it from the afs_addr_cursor struct to the afs_operation and afs_vl_cursor structs and using the error prioritisation function for accumulating errors from multiple sources (AFS tries to rotate between multiple fileservers, some of which may be inaccessible or in some state of offlinedness).
Stable-dep-of: 17ba6f0bd14f ("afs: Fix error handling with lookup via FS.InlineBulkStatus")
--- fs/afs/addr_list.c | 8 ++-- fs/afs/dir.c | 14 ++++--- fs/afs/dir_silly.c | 2 +- fs/afs/file.c | 3 -- fs/afs/fs_operation.c | 24 +++++------ fs/afs/fsclient.c | 1 + fs/afs/internal.h | 44 +++++++++++++++------ fs/afs/misc.c | 10 ++++- fs/afs/rotate.c | 58 ++++++++++++++------------- fs/afs/rxrpc.c | 17 ++++---- fs/afs/server.c | 1 - fs/afs/vl_alias.c | 2 +- fs/afs/vl_probe.c | 7 ++-- fs/afs/vl_rotate.c | 92 +++++++++++++++++++++---------------------- fs/afs/vlclient.c | 34 ++++++++++------ 15 files changed, 174 insertions(+), 143 deletions(-)
fs/afs/addr_list.c +3 -5
@@ -386,26 +386,24 @@ bool afs_iterate_addresses(struct afs_addr_cursor *ac) selected: ac->index = index;set_bit (index, &ac->tried); - ac->responded = false; + ac->call_responded = false;return true; }/* * Release an address list cursor. */ -int afs_end_cursor (struct afs_addr_cursor *ac) +void afs_end_cursor (struct afs_addr_cursor *ac) {struct afs_addr_list *alist; alist = ac->alist;if (alist) { -if (ac->responded && +if (ac->call_responded && ac->index != alist->preferred &&test_bit (ac->alist->preferred, &ac->tried))WRITE_ONCE (alist->preferred, ac->index);afs_put_addrlist (alist); ac->alist =NULL ; } - -return ac->error; }
fs/afs/dir.c +8 -6
@@ -701,8 +701,9 @@ static void afs_do_lookup_success(struct afs_operation *op) vp = &op->file[0 ]; abort_code = vp->scb.status.abort_code;if (abort_code !=0 ) { - op->ac.abort_code = abort_code; - op->error =afs_abort_to_error (abort_code); + op->call_abort_code = abort_code; +afs_op_set_error (op,afs_abort_to_error (abort_code)); + op->cumul_error.abort_code = abort_code; }break ;
@@ -854,13 +855,14 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,_debug ("nr_files %u" , op->nr_files);/* Need space for examining all the selected files */ - op->error = -ENOMEM ;if (op->nr_files >2 ) { op->more_files =kvcalloc (op->nr_files -2 ,sizeof (struct afs_vnode_param ),GFP_KERNEL ); -if (!op->more_files) +if (!op->more_files) { +afs_op_nomem (op); goto out_op; + }for (i =2 ; i < op->nr_files; i++) { vp = &op->more_files[i -2 ];
@@ -1263,7 +1265,7 @@ void afs_check_for_remote_deletion(struct afs_operation *op) {struct afs_vnode *vnode = op->file[0 ].vnode; -switch (op->ac.abort_code) { +switch (afs_op_abort_code (op)) {case VNOVNODE :set_bit (AFS_VNODE_DELETED , &vnode->flags);afs_break_callback (vnode, afs_cb_break_for_deleted);
@@ -1288,7 +1290,7 @@ static void afs_vnode_new_inode(struct afs_operation *op)/* ENOMEM or EINTR at a really inconvenient time - just abandon * the new directory on the server. */ - op->error =PTR_ERR (inode); +afs_op_accumulate_error (op,PTR_ERR (inode),0 );return ; }
fs/afs/dir_silly.c +1 -1
@@ -218,7 +218,7 @@ static int afs_do_silly_unlink(struct afs_vnode *dvnode, struct afs_vnode *vnode/* If there was a conflict with a third party, check the status of the * unlinked vnode. */ -if (op->error ==0 && (op->flags &AFS_OPERATION_DIR_CONFLICT )) { +if (op->cumul_error.error ==0 && (op->flags &AFS_OPERATION_DIR_CONFLICT )) { op->file[1 ].update_ctime = false; op->fetch_status.which =1 ; op->ops = &afs_fetch_status_operation;
fs/afs/file.c +0 -3
@@ -245,10 +245,7 @@ static void afs_fetch_data_notify(struct afs_operation *op)struct netfs_io_subrequest *subreq = req->subreq;int error =afs_op_error (op); -if (error == -ECONNABORTED ) - error =afs_abort_to_error (op->ac.abort_code); req->error = error; -if (subreq) {__set_bit (NETFS_SREQ_CLEAR_TAIL , &subreq->flags);netfs_subreq_terminated (subreq, error ?: req->actual_len, false);
fs/afs/fs_operation.c +12 -12
@@ -169,9 +169,6 @@ static void afs_end_vnode_operation(struct afs_operation *op) }afs_drop_io_locks (op); - -if (op->error == -ECONNABORTED ) - op->error =afs_abort_to_error (op->ac.abort_code); }/*
@@ -182,6 +179,8 @@ void afs_wait_for_operation(struct afs_operation *op)_enter ("" );while (afs_select_fileserver (op)) { + op->call_error =0 ; + op->call_abort_code =0 ; op->cb_s_break = op->server->cb_s_break;if (test_bit (AFS_SERVER_FL_IS_YFS , &op->server->flags) && op->ops->issue_yfs_rpc)
@@ -189,28 +188,29 @@ void afs_wait_for_operation(struct afs_operation *op)else if (op->ops->issue_afs_rpc) op->ops->issue_afs_rpc (op);else - op->ac.error = -ENOTSUPP ; + op->call_error = -ENOTSUPP ;if (op->call) {afs_wait_for_call_to_complete (op->call, &op->ac); - op->error = op->ac.error; + op->call_abort_code = op->call->abort_code; + op->call_error = op->call->error; + op->call_responded = op->call->responded; + op->ac.call_responded = true; +WRITE_ONCE (op->ac.alist->addrs[op->ac.index].last_error, + op->call_error);afs_put_call (op->call); } } -switch (op->error) { -case 0 : +if (!afs_op_error (op)) {_debug ("success" ); op->ops->success (op); -break ; -case -ECONNABORTED : + }else if (op->cumul_error.aborted) {if (op->ops->aborted) op->ops->aborted (op); - fallthrough; -default : + }else {if (op->ops->failed) op->ops->failed (op); -break ; }afs_end_vnode_operation (op);
fs/afs/fsclient.c +1 -0
@@ -1629,6 +1629,7 @@ int afs_fs_give_up_all_callbacks(struct afs_net *net, call->server =afs_use_server (server, afs_server_trace_give_up_cb);afs_make_call (ac, call,GFP_NOFS );afs_wait_for_call_to_complete (call, ac); + ret = call->error;afs_put_call (call);return ret; }
fs/afs/internal.h +31 -13
126 lines not on this page · raw message
fs/afs/misc.c +8 -2
@@ -116,6 +116,8 @@ void afs_prioritise_error(struct afs_error *e, int error, u32 abort_code) {switch (error) {case 0 : + e->aborted = false; + e->error =0 ;return ;default : if (e->error == -ETIMEDOUT ||
@@ -161,12 +163,16 @@ void afs_prioritise_error(struct afs_error *e, int error, u32 abort_code)if (e->responded)return ; e->error = error; + e->aborted = false;return ;case -ECONNABORTED : - error =afs_abort_to_error (abort_code); - fallthrough; + e->error =afs_abort_to_error (abort_code); + e->aborted = true; + e->responded = true; +return ;case -ENETRESET :/* Responded, but we seem to have changed address */ + e->aborted = false; e->responded = true; e->error = error;return ;
fs/afs/rotate.c +30 -28
174 lines not on this page · raw message
fs/afs/rxrpc.c +7 -10
@@ -408,8 +408,7 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp)rxrpc_kernel_recv_data (call->net->socket, rxcall, &msg.msg_iter, &len, false, &call->abort_code, &call->service_id); - ac->abort_code = call->abort_code; - ac->responded = true; + call->responded = true; } call->error = ret;trace_afs_call_done (call);
@@ -429,7 +428,7 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp)afs_set_call_complete (call, ret,0 ); } - ac->error = ret; + call->error = ret; call->state =AFS_CALL_COMPLETE ;_leave (" = %d" , ret); }
@@ -510,6 +509,7 @@ static void afs_deliver_to_call(struct afs_call *call) ret = -EBADMSG ;switch (ret) {case 0 : + call->responded = true;afs_queue_call_work (call);if (state ==AFS_CALL_CL_PROC_REPLY ) {if (call->op)
@@ -524,9 +524,11 @@ static void afs_deliver_to_call(struct afs_call *call) goto out;case -ECONNABORTED : ASSERTCMP(state, ==, AFS_CALL_COMPLETE); + call->responded = true;afs_log_error (call, call->abort_code); goto done;case -ENOTSUPP : + call->responded = true; abort_code =RXGEN_OPCODE ; rxrpc_kernel_abort_call(call->net->socket, call->rxcall, abort_code, ret,
@@ -573,7 +575,7 @@ static void afs_deliver_to_call(struct afs_call *call) }/* -* Wait synchronously for a call to complete and clean up the call struct. +* Wait synchronously for a call to complete. */ void afs_wait_for_call_to_complete (struct afs_call *call,struct afs_addr_cursor *ac) {
@@ -626,13 +628,8 @@ void afs_wait_for_call_to_complete(struct afs_call *call, struct afs_addr_cursor } } -spin_lock_bh (&call->state_lock); - ac->abort_code = call->abort_code; - ac->error = call->error; -spin_unlock_bh (&call->state_lock); -if (call->error ==0 || call->error == -ECONNABORTED ) - ac->responded = true; + call->responded = true; }/*
fs/afs/server.c +0 -1
@@ -437,7 +437,6 @@ static void afs_give_up_callbacks(struct afs_net *net, struct afs_server *serverstruct afs_addr_cursor ac = { .alist = alist, .index = alist->preferred, - .error =0 , };afs_fs_give_up_all_callbacks (net, server, &ac,NULL );
fs/afs/vl_alias.c +1 -1
@@ -236,7 +236,7 @@ static char *afs_vl_get_cell_name(struct afs_cell *cell, struct key *key)while (afs_select_vlserver (&vc)) {if (!test_bit (AFS_VLSERVER_FL_IS_YFS , &vc.server->flags)) { - vc.ac.error = -EOPNOTSUPP ; + vc.call_error = -EOPNOTSUPP ; skipped = true;continue ; }
fs/afs/vl_probe.c +3 -4
@@ -169,10 +169,11 @@ static bool afs_do_probe_vlserver(struct afs_net *net, call =afs_vl_get_capabilities (net, &ac, key, server, server_index);if (!IS_ERR (call)) { +afs_prioritise_error (_e, call->error, call->abort_code);afs_put_call (call); in_progress = true; }else { -afs_prioritise_error (_e,PTR_ERR (call), ac.abort_code); +afs_prioritise_error (_e,PTR_ERR (call),0 );afs_done_one_vl_probe (server, false); } }
@@ -187,12 +188,10 @@ int afs_send_vl_probes(struct afs_net *net, struct key *key, struct afs_vlserver_list *vllist) {struct afs_vlserver *server; -struct afs_error e; +struct afs_error e = {};bool in_progress = false;int i; - e.error =0 ; - e.responded = false;for (i =0 ; i < vllist->nr_servers; i++) { server = vllist->servers[i].server;if (test_bit (AFS_VLSERVER_FL_PROBED , &server->flags))
fs/afs/vl_rotate.c +46 -46
219 lines not on this page · raw message
fs/afs/vlclient.c +23 -11
@@ -161,10 +161,13 @@ struct afs_vldb_entry *afs_vl_get_entry_by_name_u(struct afs_vl_cursor *vc,trace_afs_make_vl_call (call);afs_make_call (&vc->ac, call,GFP_KERNEL );afs_wait_for_call_to_complete (call, &vc->ac); + vc->call_abort_code = call->abort_code; + vc->call_error = call->error; + vc->call_responded = call->responded;afs_put_call (call); -if (vc->ac.error) { +if (vc->call_error) {kfree (entry); -return ERR_PTR (vc->ac.error); +return ERR_PTR (vc->call_error); }return entry; }
@@ -305,11 +308,14 @@ struct afs_addr_list *afs_vl_get_addrs_u(struct afs_vl_cursor *vc,trace_afs_make_vl_call (call);afs_make_call (&vc->ac, call,GFP_KERNEL );afs_wait_for_call_to_complete (call, &vc->ac); - alist = call->ret_alist; + vc->call_abort_code = call->abort_code; + vc->call_error = call->error; + vc->call_responded = call->responded; + alist = call->ret_alist;afs_put_call (call); -if (vc->ac.error) { +if (vc->call_error) {afs_put_addrlist (alist); -return ERR_PTR (vc->ac.error); +return ERR_PTR (vc->call_error); }return alist; }
@@ -656,11 +662,14 @@ struct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_vl_cursor *vc,trace_afs_make_vl_call (call);afs_make_call (&vc->ac, call,GFP_KERNEL );afs_wait_for_call_to_complete (call, &vc->ac); - alist = call->ret_alist; + vc->call_abort_code = call->abort_code; + vc->call_error = call->error; + vc->call_responded = call->responded; + alist = call->ret_alist;afs_put_call (call); -if (vc->ac.error) { +if (vc->call_error) {afs_put_addrlist (alist); -return ERR_PTR (vc->ac.error); +return ERR_PTR (vc->call_error); }return alist; }
@@ -769,11 +778,14 @@ char *afs_yfsvl_get_cell_name(struct afs_vl_cursor *vc)trace_afs_make_vl_call (call);afs_make_call (&vc->ac, call,GFP_KERNEL );afs_wait_for_call_to_complete (call, &vc->ac); - cellname = call->ret_str; + vc->call_abort_code = call->abort_code; + vc->call_error = call->error; + vc->call_responded = call->responded; + cellname = call->ret_str;afs_put_call (call); -if (vc->ac.error) { +if (vc->call_error) {kfree (cellname); -return ERR_PTR (vc->ac.error); +return ERR_PTR (vc->call_error); }return cellname; }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 179/346 afs: Fix error handling with lookup via FS.InlineBulkStatus
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
[ Upstream commit 17ba6f0bd14fe3ac606aac6bebe5e69bdaad8ba1 ]
When afs does a lookup, it tries to use FS.InlineBulkStatus to preemptively look up a bunch of files in the parent directory and cache this locally, on the basis that we might want to look at them too (for example if someone does an ls on a directory, they may want want to then stat every file listed).
FS.InlineBulkStatus can be considered a compound op with the normal abort code applying to the compound as a whole. Each status fetch within the compound is then given its own individual abort code - but assuming no error that prevents the bulk fetch from returning the compound result will be 0, even if all the constituent status fetches failed.
At the conclusion of afs_do_lookup(), we should use the abort code from the appropriate status to determine the error to return, if any - but instead it is assumed that we were successful if the op as a whole succeeded and we return an incompletely initialised inode, resulting in ENOENT, no matter the actual reason. In the particular instance reported, a vnode with no permission granted to be accessed is being given a UAEACCES abort code which should be reported as EACCES, but is instead being reported as ENOENT.
Fix this by abandoning the inode (which will be cleaned up with the op) if file[1] has an abort code indicated and turn that abort code into an error instead.
Whilst we're at it, add a tracepoint so that the abort codes of the individual subrequests of FS.InlineBulkStatus can be logged. At the moment only the container abort code can be 0.
--- fs/afs/dir.c | 12 +++++++++--- include/trace/events/afs.h | 25 +++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-)
fs/afs/dir.c +9 -3
@@ -716,6 +716,8 @@ static void afs_do_lookup_success(struct afs_operation *op)break ; } +if (vp->scb.status.abort_code) +trace_afs_bulkstat_error (op, &vp->fid, i, vp->scb.status.abort_code);if (!vp->scb.have_status && !vp->scb.have_error)continue ;
@@ -905,12 +907,16 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,afs_begin_vnode_operation (op);afs_wait_for_operation (op); } - inode =ERR_PTR (afs_op_error (op)); out_op:if (!afs_op_error (op)) { - inode = &op->file[1 ].vnode->netfs.inode; - op->file[1 ].vnode =NULL ; +if (op->file[1 ].scb.status.abort_code) { +afs_op_accumulate_error (op, -ECONNABORTED , + op->file[1 ].scb.status.abort_code); + }else { + inode = &op->file[1 ].vnode->netfs.inode; + op->file[1 ].vnode =NULL ; + } }if (op->file[0 ].scb.have_status)
include/trace/events/afs.h +25 -0
@@ -1216,6 +1216,31 @@ TRACE_EVENT(afs_file_error, __print_symbolic(__entry->where, afs_file_errors)) ); +TRACE_EVENT (afs_bulkstat_error, + TP_PROTO(struct afs_operation *op, struct afs_fid *fid, unsigned int index, s32 abort), + +TP_ARGS (op, fid, index, abort), + +TP_STRUCT__entry ( + __field_struct(struct afs_fid, fid) + __field(unsigned int, op) + __field(unsigned int, index) +__field (s32, abort) + ), + +TP_fast_assign ( + __entry->op = op->debug_id; + __entry->fid = *fid; + __entry->index = index; + __entry->abort = abort; + ), + +TP_printk ("OP=%08x[%02x] %llx:%llx:%x a=%d" , + __entry->op, __entry->index, + __entry->fid.vid, __entry->fid.vnode, __entry->fid.unique, + __entry->abort) + ); + TRACE_EVENT(afs_cm_no_server, TP_PROTO(struct afs_call *call, struct sockaddr_rxrpc *srx),
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 180/346 tcp: Add memory barrier to tcp_push()
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Salvatore Dipietro <[email protected]>
[ Upstream commit 7267e8dcad6b2f9fce05a6a06335d7040acbc2b6 ]
On CPUs with weak memory models, reads and updates performed by tcp_push to the sk variables can get reordered leaving the socket throttled when it should not. The tasklet running tcp_wfree() may also not observe the memory updates in time and will skip flushing any packets throttled by tcp_push(), delaying the sending. This can pathologically cause 40ms extra latency due to bad interactions with delayed acks.
Adding a memory barrier in tcp_push removes the bug, similarly to the previous commit bf06200e732d ("tcp: tsq: fix nonagle handling"). smp_mb__after_atomic() is used to not incur in unnecessary overhead on x86 since not affected.
Patch has been tested using an AWS c7g.2xlarge instance with Ubuntu 22.04 and Apache Tomcat 9.0.83 running the basic servlet below:
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class HelloWorldServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
OutputStreamWriter osw = new OutputStreamWriter(response.getOutputStream(),"UTF-8");
String s = "a".repeat(3096);
osw.write(s,0,s.length());
osw.flush();
}
}Load was applied using wrk2 (https://github.com/kinvolk/wrk2) from an AWS c6i.8xlarge instance. Before the patch an additional 40ms latency from P99.99+ values is observed while, with the patch, the extra latency disappears.
No patch and tcp_autocorking=1
./wrk -t32 -c128 -d40s --latency -R10000 http://172.31.60.173:8080/hello/hello
...
50.000% 0.91ms 75.000% 1.13ms 90.000% 1.46ms 99.000% 1.74ms 99.900% 1.89ms 99.990% 41.95ms <<< 40+ ms extra latency 99.999% 48.32ms 100.000% 48.96ms
With patch and tcp_autocorking=1
./wrk -t32 -c128 -d40s --latency -R10000 http://172.31.60.173:8080/hello/hello
...
50.000% 0.90ms 75.000% 1.13ms 90.000% 1.45ms 99.000% 1.72ms 99.900% 1.83ms 99.990% 2.11ms <<< no 40+ ms extra latency 99.999% 2.53ms 100.000% 2.62ms
Patch has been also tested on x86 (m7i.2xlarge instance) which it is not affected by this issue and the patch doesn't introduce any additional delay.
--- net/ipv4/tcp.c | 1 + 1 file changed, 1 insertion(+)
net/ipv4/tcp.c +1 -0
@@ -722,6 +722,7 @@ void tcp_push(struct sock *sk, int flags, int mss_now,if (!test_bit (TSQ_THROTTLED , &sk->sk_tsq_flags)) {NET_INC_STATS (sock_net (sk),LINUX_MIB_TCPAUTOCORKING );set_bit (TSQ_THROTTLED , &sk->sk_tsq_flags); +smp_mb__after_atomic (); }/* It is possible TX completion already happened * before we set TSQ_THROTTLED.
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 181/346 selftest: Dont reuse port for SO_INCOMING_CPU test.
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <[email protected]>
[ Upstream commit 97de5a15edf2d22184f5ff588656030bbb7fa358 ]
Jakub reported that ASSERT_EQ(cpu, i) in so_incoming_cpu.c seems to fire somewhat randomly.
# # RUN so_incoming_cpu.before_reuseport.test3 ...
# # so_incoming_cpu.c:191:test3:Expected cpu (32) == i (0) # # test3: Test terminated by assertion
# # FAIL so_incoming_cpu.before_reuseport.test3
# not ok 3 so_incoming_cpu.before_reuseport.test3
When the test failed, not-yet-accepted CLOSE_WAIT sockets received SYN with a "challenging" SEQ number, which was sent from an unexpected CPU that did not create the receiver.
The test basically does:
1. for each cpu:
1-1. create a server
1-2. set SO_INCOMING_CPU
2. for each cpu:
2-1. set cpu affinity
2-2. create some clients
2-3. let clients connect() to the server on the same cpu 2-4. close() clients
3. for each server:
3-1. accept() all child sockets
3-2. check if all children have the same SO_INCOMING_CPU with the server
The root cause was the close() in 2-4. and net.ipv4.tcp_tw_reuse.
In a loop of 2., close() changed the client state to FIN_WAIT_2, and the peer transitioned to CLOSE_WAIT.
In another loop of 2., connect() happened to select the same port of the FIN_WAIT_2 socket, and it was reused as the default value of net.ipv4.tcp_tw_reuse is 2.
As a result, the new client sent SYN to the CLOSE_WAIT socket from a different CPU, and the receiver's sk_incoming_cpu was overwritten with unexpected CPU ID.
Also, the SYN had a different SEQ number, so the CLOSE_WAIT socket responded with Challenge ACK. The new client properly returned RST and effectively killed the CLOSE_WAIT socket.
This way, all clients were created successfully, but the error was detected later by 3-2., ASSERT_EQ(cpu, i).
To avoid the failure, let's make sure that (i) the number of clients is less than the number of available ports and (ii) such reuse never happens.
--- tools/testing/selftests/net/so_incoming_cpu.c | 68 ++++++++++++++----- 1 file changed, 50 insertions(+), 18 deletions(-)
tools/testing/selftests/net/so_incoming_cpu.c +50 -18
@@ -3,19 +3,16 @@#define _GNU_SOURCE#include <sched.h> +#include <fcntl.h> +#include <netinet/in.h> #include <sys/socket.h> #include <sys/sysinfo.h> #include "../kselftest_harness.h" -#define CLIENT_PER_SERVER 32/* More sockets, more reliable */ -#define NR_SERVER self->nproc -#define NR_CLIENT (CLIENT_PER_SERVER * NR_SERVER) -FIXTURE (so_incoming_cpu) { -int nproc;int *servers;union {struct sockaddr addr;
@@ -56,12 +53,47 @@ FIXTURE_VARIANT_ADD(so_incoming_cpu, after_all_listen) .when_to_set = AFTER_ALL_LISTEN, }; +static void write_sysctl (struct __test_metadata *_metadata, +char *filename,char *string) +{ +int fd, len, ret; + + fd =open (filename,O_WRONLY ); +ASSERT_NE (fd,-1 ); + + len =strlen (string); + ret =write (fd, string, len); +ASSERT_EQ (ret, len); +} + +static void setup_netns (struct __test_metadata *_metadata) +{ +ASSERT_EQ (unshare (CLONE_NEWNET ),0 ); +ASSERT_EQ (system ("ip link set lo up" ),0 ); + +write_sysctl (_metadata,"/proc/sys/net/ipv4/ip_local_port_range" ,"10000 60001" ); +write_sysctl (_metadata,"/proc/sys/net/ipv4/tcp_tw_reuse" ,"0" ); +} + +#define NR_PORT (60001 - 10000 - 1) +#define NR_CLIENT_PER_SERVER_DEFAULT 32 +static int nr_client_per_server, nr_server, nr_client; +FIXTURE_SETUP (so_incoming_cpu) { - self->nproc =get_nprocs (); -ASSERT_LE (2 , self->nproc); +setup_netns (_metadata); + + nr_server =get_nprocs (); +ASSERT_LE (2 , nr_server); + +if (NR_CLIENT_PER_SERVER_DEFAULT * nr_server <NR_PORT ) + nr_client_per_server =NR_CLIENT_PER_SERVER_DEFAULT ; +else + nr_client_per_server =NR_PORT / nr_server; + + nr_client = nr_client_per_server * nr_server; - self->servers =malloc (sizeof (int ) *NR_SERVER ); + self->servers =malloc (sizeof (int ) * nr_server);ASSERT_NE (self->servers,NULL ); self->in_addr.sin_family =AF_INET ;
@@ -74,7 +106,7 @@ FIXTURE_TEARDOWN(so_incoming_cpu) {int i; -for (i =0 ; i <NR_SERVER ; i++) +for (i =0 ; i < nr_server; i++)close (self->servers[i]);free (self->servers);
@@ -110,10 +142,10 @@ int create_server(struct __test_metadata *_metadata,if (variant->when_to_set ==BEFORE_LISTEN )set_so_incoming_cpu (_metadata, fd, cpu); -/* We don't use CLIENT_PER_SERVER here not to block +/* We don't use nr_client_per_server here not to block * this test at connect() if SO_INCOMING_CPU is broken. */ - ret =listen (fd,NR_CLIENT ); + ret =listen (fd, nr_client);ASSERT_EQ (ret,0 );if (variant->when_to_set ==AFTER_LISTEN )
@@ -128,7 +160,7 @@ void create_servers(struct __test_metadata *_metadata, {int i, ret; -for (i =0 ; i <NR_SERVER ; i++) { +for (i =0 ; i < nr_server; i++) { self->servers[i] =create_server (_metadata, self, variant, i);if (i ==0 ) {
@@ -138,7 +170,7 @@ void create_servers(struct __test_metadata *_metadata, }if (variant->when_to_set ==AFTER_ALL_LISTEN ) { -for (i =0 ; i <NR_SERVER ; i++) +for (i =0 ; i < nr_server; i++)set_so_incoming_cpu (_metadata, self->servers[i], i); } }
@@ -149,7 +181,7 @@ void create_clients(struct __test_metadata *_metadata,cpu_set_t cpu_set;int i, j, fd, ret; -for (i =0 ; i <NR_SERVER ; i++) { +for (i =0 ; i < nr_server; i++) {CPU_ZERO (&cpu_set);CPU_SET (i, &cpu_set);
@@ -162,7 +194,7 @@ void create_clients(struct __test_metadata *_metadata, ret =sched_setaffinity (0 ,sizeof (cpu_set), &cpu_set);ASSERT_EQ (ret,0 ); -for (j =0 ; j <CLIENT_PER_SERVER ; j++) { +for (j =0 ; j < nr_client_per_server; j++) { fd =socket (AF_INET ,SOCK_STREAM ,0 );ASSERT_NE (fd,-1 );
@@ -180,8 +212,8 @@ void verify_incoming_cpu(struct __test_metadata *_metadata,int i, j, fd, cpu, ret, total =0 ;socklen_t len =sizeof (int ); -for (i =0 ; i <NR_SERVER ; i++) { -for (j =0 ; j <CLIENT_PER_SERVER ; j++) { +for (i =0 ; i < nr_server; i++) { +for (j =0 ; j < nr_client_per_server; j++) {/* If we see -EAGAIN here, SO_INCOMING_CPU is broken */ fd =accept (self->servers[i], &self->addr, &self->addrlen);ASSERT_NE (fd,-1 );
@@ -195,7 +227,7 @@ void verify_incoming_cpu(struct __test_metadata *_metadata, } } -ASSERT_EQ (total,NR_CLIENT ); +ASSERT_EQ (total, nr_client);TH_LOG ("SO_INCOMING_CPU is very likely to be " "working correctly with %d sockets." , total); }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 182/346 netlink: fix potential sleeping issue in mqueue_flush_file
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhengchao Shao <[email protected]>
[ Upstream commit 234ec0b6034b16869d45128b8cd2dc6ffe596f04 ]
I analyze the potential sleeping issue of the following processes:
Thread A Thread B ... netlink_create //ref = 1 do_mq_notify ... sock = netlink_getsockbyfilp ... //ref = 2 info->notify_sock = sock; ... ... netlink_sendmsg
... skb = netlink_alloc_large_skb //skb->head is vmalloced
... netlink_unicast
... sk = netlink_getsockbyportid //ref = 3
... netlink_sendskb
... __netlink_sendskb
... skb_queue_tail //put skb to sk_receive_queue
... sock_put //ref = 2
... ...
... netlink_release
... deferred_put_nlk_sk //ref = 1mqueue_flush_file
spin_lock
remove_notification
netlink_sendskb
sock_put //ref = 0
sk_free
...
__sk_destruct
netlink_sock_destruct
skb_queue_purge //get skb from sk_receive_queue
...
__skb_queue_purge_reason
kfree_skb_reason
__kfree_skb
...
skb_release_all
skb_release_head_state
netlink_skb_destructor
vfree(skb->head) //sleeping while holding spinlockIn netlink_sendmsg, if the memory pointed to by skb->head is allocated by vmalloc, and is put to sk_receive_queue queue, also the skb is not freed. When the mqueue executes flush, the sleeping bug will occur. Use vfree_atomic instead of vfree in netlink_skb_destructor to solve the issue.
--- net/netlink/af_netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/netlink/af_netlink.c +1 -1
@@ -374,7 +374,7 @@ static void netlink_skb_destructor(struct sk_buff *skb)if (is_vmalloc_addr (skb->head)) {if (!skb->cloned || !atomic_dec_return (&(skb_shinfo (skb)->dataref))) -vfree (skb->head); +vfree_atomic (skb->head); skb->head =NULL ; }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 183/346 ipv6: init the accept_queues spinlocks in inet6_create
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhengchao Shao <[email protected]>
[ Upstream commit 435e202d645c197dcfd39d7372eb2a56529b6640 ]
In commit 198bc90e0e73("tcp: make sure init the accept_queue's spinlocks once"), the spinlocks of accept_queue are initialized only when socket is created in the inet4 scenario. The locks are not initialized when socket is created in the inet6 scenario. The kernel reports the following error:
INFO: trying to register non-static key.
The code is fine but needs lockdep annotation, or maybe
you didn't initialize this object before use?
turning off the locking correctness validator.
Hardware name: Red Hat KVM, BIOS 0.5.1 01/01/2011 Call Trace: <TASK> dump_stack_lvl (lib/dump_stack.c:107) register_lock_class (kernel/locking/lockdep.c:1289) __lock_acquire (kernel/locking/lockdep.c:5015) lock_acquire.part.0 (kernel/locking/lockdep.c:5756) _raw_spin_lock_bh (kernel/locking/spinlock.c:178) inet_csk_listen_stop (net/ipv4/inet_connection_sock.c:1386) tcp_disconnect (net/ipv4/tcp.c:2981) inet_shutdown (net/ipv4/af_inet.c:935) __sys_shutdown (./include/linux/file.h:32 net/socket.c:2438) __x64_sys_shutdown (net/socket.c:2445) do_syscall_64 (arch/x86/entry/common.c:52) entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:129) RIP: 0033:0x7f52ecd05a3d Code: 5b 41 5c c3 66 0f 1f 84 00 00 00 00 00 f3 0f 1e fa 48 89 f8 48 89 f7
48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d ab a3 0e 00 f7 d8 64 89 01 48
RSP: 002b:00007f52ecf5dde8 EFLAGS: 00000293 ORIG_RAX: 0000000000000030
RAX: ffffffffffffffda RBX: 00007f52ecf5e640 RCX: 00007f52ecd05a3d
RDX: 00007f52ecc8b188 RSI: 0000000000000000 RDI: 0000000000000004
RBP: 00007f52ecf5de20 R08: 00007ffdae45c69f R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000293 R12: 00007f52ecf5e640
R13: 0000000000000000 R14: 00007f52ecc8b060 R15: 00007ffdae45c6e0
--- net/ipv6/af_inet6.c | 3 +++ 1 file changed, 3 insertions(+)
net/ipv6/af_inet6.c +3 -0
@@ -199,6 +199,9 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol,if (INET_PROTOSW_REUSE & answer_flags) sk->sk_reuse =SK_CAN_REUSE ; +if (INET_PROTOSW_ICSK & answer_flags) +inet_init_csk_locks (sk); + inet =inet_sk (sk);inet_assign_bit (IS_ICSK , sk,INET_PROTOSW_ICSK & answer_flags);
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 184/346 selftests: fill in some missing configs for net
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jakub Kicinski <[email protected]>
[ Upstream commit 04fe7c5029cbdbcdb28917f09a958d939a8f19f7 ]
We are missing a lot of config options from net selftests, it seems:
tun/tap: CONFIG_TUN, CONFIG_MACVLAN, CONFIG_MACVTAP
fib_tests: CONFIG_NET_SCH_FQ_CODEL
l2tp: CONFIG_L2TP, CONFIG_L2TP_V3, CONFIG_L2TP_IP, CONFIG_L2TP_ETH
sctp-vrf: CONFIG_INET_DIAG
txtimestamp: CONFIG_NET_CLS_U32
vxlan_mdb: CONFIG_BRIDGE_VLAN_FILTERING
gre_gso: CONFIG_NET_IPGRE_DEMUX, CONFIG_IP_GRE, CONFIG_IPV6_GRE
srv6_end_dt*_l3vpn: CONFIG_IPV6_SEG6_LWTUNNEL
ip_local_port_range: CONFIG_MPTCP
fib_test: CONFIG_NET_CLS_BASIC
rtnetlink: CONFIG_MACSEC, CONFIG_NET_SCH_HTB, CONFIG_XFRM_INTERFACE
CONFIG_NET_IPGRE, CONFIG_BONDING
fib_nexthops: CONFIG_MPLS, CONFIG_MPLS_ROUTING
vxlan_mdb: CONFIG_NET_ACT_GACT
tls: CONFIG_TLS, CONFIG_CRYPTO_CHACHA20POLY1305
psample: CONFIG_PSAMPLE
fcnal: CONFIG_TCP_MD5SIGTry to add them in a semi-alphabetical order.
--- tools/testing/selftests/net/config | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+)
tools/testing/selftests/net/config +28 -0
@@ -1,5 +1,6 @@ CONFIG_USER_NS=y CONFIG_NET_NS=y +CONFIG_BONDING=m CONFIG_BPF_SYSCALL=y CONFIG_TEST_BPF=m CONFIG_NUMA=y
@@ -14,9 +15,13 @@ CONFIG_VETH=y CONFIG_NET_IPVTI=y CONFIG_IPV6_VTI=y CONFIG_DUMMY=y +CONFIG_BRIDGE_VLAN_FILTERING=y CONFIG_BRIDGE=y +CONFIG_CRYPTO_CHACHA20POLY1305=m CONFIG_VLAN_8021Q=y CONFIG_IFB=y +CONFIG_INET_DIAG=y +CONFIG_IP_GRE=m CONFIG_NETFILTER=y CONFIG_NETFILTER_ADVANCED=y CONFIG_NF_CONNTRACK=m
@@ -25,15 +30,36 @@ CONFIG_IP6_NF_IPTABLES=m CONFIG_IP_NF_IPTABLES=m CONFIG_IP6_NF_NAT=m CONFIG_IP_NF_NAT=m +CONFIG_IPV6_GRE=m +CONFIG_IPV6_SEG6_LWTUNNEL=y +CONFIG_L2TP_ETH=m +CONFIG_L2TP_IP=m +CONFIG_L2TP=m +CONFIG_L2TP_V3=y +CONFIG_MACSEC=m +CONFIG_MACVLAN=y +CONFIG_MACVTAP=y +CONFIG_MPLS=y +CONFIG_MPTCP=y CONFIG_NF_TABLES=m CONFIG_NF_TABLES_IPV6=y CONFIG_NF_TABLES_IPV4=y CONFIG_NFT_NAT=m +CONFIG_NET_ACT_GACT=m +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_IPGRE_DEMUX=m +CONFIG_NET_IPGRE=m +CONFIG_NET_SCH_FQ_CODEL=m +CONFIG_NET_SCH_HTB=m CONFIG_NET_SCH_FQ=m CONFIG_NET_SCH_ETF=m CONFIG_NET_SCH_NETEM=y +CONFIG_PSAMPLE=m +CONFIG_TCP_MD5SIG=y CONFIG_TEST_BLACKHOLE_DEV=m CONFIG_KALLSYMS=y +CONFIG_TLS=m CONFIG_TRACEPOINTS=y CONFIG_NET_DROP_MONITOR=m CONFIG_NETDEVSIM=m
@@ -48,7 +74,9 @@ CONFIG_BAREUDP=m CONFIG_IPV6_IOAM6_LWTUNNEL=y CONFIG_CRYPTO_SM4_GENERIC=y CONFIG_AMT=m +CONFIG_TUN=y CONFIG_VXLAN=m CONFIG_IP_SCTP=m CONFIG_NETFILTER_XT_MATCH_POLICY=m CONFIG_CRYPTO_ARIA=y +CONFIG_XFRM_INTERFACE=m
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 185/346 net/sched: flower: Fix chain template offload
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ido Schimmel <[email protected]>
[ Upstream commit 32f2a0afa95fae0d1ceec2ff06e0e816939964b8 ]
When a qdisc is deleted from a net device the stack instructs the underlying driver to remove its flow offload callback from the associated filter block using the 'FLOW_BLOCK_UNBIND' command. The stack then continues to replay the removal of the filters in the block for this driver by iterating over the chains in the block and invoking the 'reoffload' operation of the classifier being used. In turn, the classifier in its 'reoffload' operation prepares and emits a 'FLOW_CLS_DESTROY' command for each filter.
However, the stack does not do the same for chain templates and the underlying driver never receives a 'FLOW_CLS_TMPLT_DESTROY' command when a qdisc is deleted. This results in a memory leak [1] which can be reproduced using [2].
Fix by introducing a 'tmplt_reoffload' operation and have the stack invoke it with the appropriate arguments as part of the replay. Implement the operation in the sole classifier that supports chain templates (flower) by emitting the 'FLOW_CLS_TMPLT_{CREATE,DESTROY}' command based on whether a flow offload callback is being bound to a filter block or being unbound from one.
As far as I can tell, the issue happens since cited commit which reordered tcf_block_offload_unbind() before tcf_block_flush_all_chains() in __tcf_block_put(). The order cannot be reversed as the filter block is expected to be freed after flushing all the chains.
[1]
unreferenced object 0xffff888107e28800 (size 2048):
comm "tc", pid 1079, jiffies 4294958525 (age 3074.287s) hex dump (first 32 bytes):
b1 a6 7c 11 81 88 ff ff e0 5b b3 10 81 88 ff ff ..|......[......
01 00 00 00 00 00 00 00 e0 aa b0 84 ff ff ff ff ................
backtrace:
[<ffffffff81c06a68>] __kmem_cache_alloc_node+0x1e8/0x320
[<ffffffff81ab374e>] __kmalloc+0x4e/0x90
[<ffffffff832aec6d>] mlxsw_sp_acl_ruleset_get+0x34d/0x7a0
[<ffffffff832bc195>] mlxsw_sp_flower_tmplt_create+0x145/0x180
[<ffffffff832b2e1a>] mlxsw_sp_flow_block_cb+0x1ea/0x280
[<ffffffff83a10613>] tc_setup_cb_call+0x183/0x340
[<ffffffff83a9f85a>] fl_tmplt_create+0x3da/0x4c0
[<ffffffff83a22435>] tc_ctl_chain+0xa15/0x1170
[<ffffffff838a863c>] rtnetlink_rcv_msg+0x3cc/0xed0
[<ffffffff83ac87f0>] netlink_rcv_skb+0x170/0x440
[<ffffffff83ac6270>] netlink_unicast+0x540/0x820
[<ffffffff83ac6e28>] netlink_sendmsg+0x8d8/0xda0
[<ffffffff83793def>] ____sys_sendmsg+0x30f/0xa80
[<ffffffff8379d29a>] ___sys_sendmsg+0x13a/0x1e0
[<ffffffff8379d50c>] __sys_sendmsg+0x11c/0x1f0
[<ffffffff843b9ce0>] do_syscall_64+0x40/0xe0
unreferenced object 0xffff88816d2c0400 (size 1024):
comm "tc", pid 1079, jiffies 4294958525 (age 3074.287s)
hex dump (first 32 bytes):
40 00 00 00 00 00 00 00 57 f6 38 be 00 00 00 00 @.......W.8.....
10 04 2c 6d 81 88 ff ff 10 04 2c 6d 81 88 ff ff ..,m......,m....
backtrace:
[<ffffffff81c06a68>] __kmem_cache_alloc_node+0x1e8/0x320
[<ffffffff81ab36c1>] __kmalloc_node+0x51/0x90
[<ffffffff81a8ed96>] kvmalloc_node+0xa6/0x1f0
[<ffffffff82827d03>] bucket_table_alloc.isra.0+0x83/0x460
[<ffffffff82828d2b>] rhashtable_init+0x43b/0x7c0
[<ffffffff832aed48>] mlxsw_sp_acl_ruleset_get+0x428/0x7a0
[<ffffffff832bc195>] mlxsw_sp_flower_tmplt_create+0x145/0x180
[<ffffffff832b2e1a>] mlxsw_sp_flow_block_cb+0x1ea/0x280
[<ffffffff83a10613>] tc_setup_cb_call+0x183/0x340
[<ffffffff83a9f85a>] fl_tmplt_create+0x3da/0x4c0
[<ffffffff83a22435>] tc_ctl_chain+0xa15/0x1170
[<ffffffff838a863c>] rtnetlink_rcv_msg+0x3cc/0xed0
[<ffffffff83ac87f0>] netlink_rcv_skb+0x170/0x440
[<ffffffff83ac6270>] netlink_unicast+0x540/0x820
[<ffffffff83ac6e28>] netlink_sendmsg+0x8d8/0xda0
[<ffffffff83793def>] ____sys_sendmsg+0x30f/0xa80[2]
# tc qdisc add dev swp1 clsact # tc chain add dev swp1 ingress proto ip chain 1 flower dst_ip 0.0.0.0/32 # tc qdisc del dev swp1 clsact # devlink dev reload pci/0000:06:00.0
--- include/net/sch_generic.h | 4 ++++ net/sched/cls_api.c | 9 ++++++++- net/sched/cls_flower.c | 23 +++++++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-)
include/net/sch_generic.h +4 -0
@@ -375,6 +375,10 @@ struct tcf_proto_ops {struct nlattr **tca, struct netlink_ext_ack *extack);void (*tmplt_destroy)(void *tmplt_priv); +void (*tmplt_reoffload)(struct tcf_chain *chain, +bool add, +flow_setup_cb_t *cb, +void *cb_priv);struct tcf_exts * (*get_exts)(const struct tcf_proto *tp,u32 handle);
net/sched/cls_api.c +8 -1
@@ -1536,6 +1536,9 @@ tcf_block_playback_offloads(struct tcf_block *block, flow_setup_cb_t *cb, chain_prev = chain, chain = __tcf_get_next_chain(block, chain), tcf_chain_put(chain_prev)) { +if (chain->tmplt_ops && add) + chain->tmplt_ops->tmplt_reoffload (chain, true, cb, + cb_priv); for (tp = __tcf_get_next_proto(chain, NULL); tp; tp_prev = tp, tp = __tcf_get_next_proto(chain, tp),
@@ -1551,6 +1554,9 @@ tcf_block_playback_offloads(struct tcf_block *block, flow_setup_cb_t *cb, goto err_playback_remove; } } +if (chain->tmplt_ops && !add) + chain->tmplt_ops->tmplt_reoffload (chain, false, cb, + cb_priv); }return 0 ;
@@ -2971,7 +2977,8 @@ static int tc_chain_tmplt_add(struct tcf_chain *chain, struct net *net, ops =tcf_proto_lookup_ops (name, true, extack);if (IS_ERR (ops))return PTR_ERR (ops); -if (!ops->tmplt_create || !ops->tmplt_destroy || !ops->tmplt_dump) { +if (!ops->tmplt_create || !ops->tmplt_destroy || !ops->tmplt_dump || + !ops->tmplt_reoffload) {NL_SET_ERR_MSG (extack,"Chain templates are not supported with specified classifier" );module_put (ops->owner);return -EOPNOTSUPP ;
net/sched/cls_flower.c +23 -0
@@ -2721,6 +2721,28 @@ static void fl_tmplt_destroy(void *tmplt_priv)kfree (tmplt); } +static void fl_tmplt_reoffload (struct tcf_chain *chain,bool add, +flow_setup_cb_t *cb,void *cb_priv) +{ +struct fl_flow_tmplt *tmplt = chain->tmplt_priv; +struct flow_cls_offload cls_flower = {}; + + cls_flower.rule =flow_rule_alloc (0 ); +if (!cls_flower.rule) +return ; + + cls_flower.common.chain_index = chain->index; + cls_flower.command = add ?FLOW_CLS_TMPLT_CREATE : +FLOW_CLS_TMPLT_DESTROY ; + cls_flower.cookie = (unsigned long ) tmplt; + cls_flower.rule->match.dissector = &tmplt->dissector; + cls_flower.rule->match.mask = &tmplt->mask; + cls_flower.rule->match.key = &tmplt->dummy_key; + +cb (TC_SETUP_CLSFLOWER , &cls_flower, cb_priv); +kfree (cls_flower.rule); +} +static int fl_dump_key_val (struct sk_buff *skb,void *val,int val_type,void *mask,int mask_type,int len)
@@ -3628,6 +3650,7 @@ static struct tcf_proto_ops cls_fl_ops __read_mostly = { .bind_class = fl_bind_class, .tmplt_create = fl_tmplt_create, .tmplt_destroy = fl_tmplt_destroy, + .tmplt_reoffload = fl_tmplt_reoffload, .tmplt_dump = fl_tmplt_dump, .get_exts = fl_get_exts, .owner = THIS_MODULE,
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 186/346 net/mlx5e: Fix operation precedence bug in port timestamping napi_poll context
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rahul Rameshbabu <[email protected]>
[ Upstream commit 3876638b2c7ebb2c9d181de1191db0de8cac143a ]
Indirection (*) is of lower precedence than postfix increment (++). Logic in napi_poll context would cause an out-of-bound read by first increment the pointer address by byte address space and then dereference the value. Rather, the intended logic was to dereference first and then increment the underlying value.
--- drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c +1 -1
@@ -213,7 +213,7 @@ static void mlx5e_ptp_handle_ts_cqe(struct mlx5e_ptpsq *ptpsq,mlx5e_ptpsq_mark_ts_cqes_undelivered (ptpsq, hwtstamp); out:napi_consume_skb (skb, budget); - md_buff[*md_buff_sz++] = metadata_id; + md_buff[(*md_buff_sz)++] = metadata_id;if (unlikely (mlx5e_ptp_metadata_map_unhealthy (&ptpsq->metadata_map)) && !test_and_set_bit (MLX5E_SQ_STATE_RECOVERING , &sq->state))queue_work (ptpsq->txqsq.priv->wq, &ptpsq->report_unhealthy_work);
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 187/346 net/mlx5e: Fix inconsistent hairpin RQT sizes
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tariq Toukan <[email protected]>
[ Upstream commit c20767fd45e82d64352db82d4fc8d281a43e4783 ]
The processing of traffic in hairpin queues occurs in HW/FW and does not involve the cpus, hence the upper bound on max num channels does not apply to them. Using this bound for the hairpin RQT max_table_size is wrong. It could be too small, and cause the error below [1]. As the RQT size provided on init does not get modified later, use the same value for both actual and max table sizes.
[1]mlx5_core 0000:08:00.1: mlx5_cmd_out_err:805:(pid 1200): CREATE_RQT(0x916) op_mod(0x0) failed, status bad parameter(0x3), syndrome (0x538faf), err(-22)
--- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +1 -1
@@ -761,7 +761,7 @@ static int mlx5e_hairpin_create_indirect_rqt(struct mlx5e_hairpin *hp) err =mlx5e_rss_params_indir_init (&indir, mdev,mlx5e_rqt_size (mdev, hp->num_channels), -mlx5e_rqt_size (mdev, priv->max_nch)); +mlx5e_rqt_size (mdev, hp->num_channels));if (err)return err;
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 188/346 net/mlx5e: Fix peer flow lists handling
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vlad Buslov <[email protected]>
[ Upstream commit d76fdd31f953ac5046555171620f2562715e9b71 ]
The cited change refactored mlx5e_tc_del_fdb_peer_flow() to only clear DUP flag when list of peer flows has become empty. However, if any concurrent user holds a reference to a peer flow (for example, the neighbor update workqueue task is updating peer flow's parent encap entry concurrently), then the flow will not be removed from the peer list and, consecutively, DUP flag will remain set. Since mlx5e_tc_del_fdb_peers_flow() calls mlx5e_tc_del_fdb_peer_flow() for every possible peer index the algorithm will try to remove the flow from eswitch instances that it has never peered with causing either NULL pointer dereference when trying to remove the flow peer list head of peer_index that was never initialized or a warning if the list debug config is enabled[0].
Fix the issue by always removing the peer flow from the list even when not releasing the last reference to it.
[0]:
[ 3102.985806] ------------[ cut here ]------------ [ 3102.986223] list_del corruption, ffff888139110698->next is NULL [ 3102.986757] WARNING: CPU: 2 PID: 22109 at lib/list_debug.c:53 __list_del_entry_valid_or_report+0x4f/0xc0 [ 3102.987561] Modules linked in: act_ct nf_flow_table bonding act_tunnel_key act_mirred act_skbedit vxlan cls_matchall nfnetlink_cttimeout act_gact cls_flower sch_ingress mlx5_vdpa vringh vhost_iotlb vdpa openvswitch nsh xt_MASQUERADE nf_conntrack_netlink nfnetlink iptable_nat xt_addrtype xt_conntrack nf_nat br_netfilter rpcsec_gss_krb5 auth_rpcg ss oid_registry overlay rpcrdma rdma_ucm ib_iser libiscsi scsi_transport_iscsi ib_umad rdma_cm ib_ipoib iw_cm ib_cm mlx5_ib ib_uverbs ib_core mlx5_core [last unloaded: bonding] [ 3102.991113] CPU: 2 PID: 22109 Comm: revalidator28 Not tainted 6.6.0-rc6+ #3 [ 3102.991695] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.13.0-0-gf21b5a4aeb02-prebuilt.qemu.org 04/01/2014 [ 3102.992605] RIP: 0010:__list_del_entry_valid_or_report+0x4f/0xc0 [ 3102.993122] Code: 39 c2 74 56 48 8b 32 48 39 fe 75 62 48 8b 51 08 48 39 f2 75 73 b8 01 00 00 00 c3 48 89 fe 48 c7 c7 48 fd 0a 82 e8 41 0b ad ff <0f> 0b 31 c0 c3 48 89 fe 48 c7 c7 70 fd 0a 82 e8 2d 0b ad ff 0f 0b [ 3102.994615] RSP: 0018:ffff8881383e7710 EFLAGS: 00010286 [ 3102.995078] RAX: 0000000000000000 RBX: 0000000000000002 RCX: 0000000000000000 [ 3102.995670] RDX: 0000000000000001 RSI: ffff88885f89b640 RDI: ffff88885f89b640 [ 3102.997188] DEL flow 00000000be367878 on port 0 [ 3102.998594] RBP: dead000000000122 R08: 0000000000000000 R09: c0000000ffffdfff [ 3102.999604] R10: 0000000000000008 R11: ffff8881383e7598 R12: dead000000000100 [ 3103.000198] R13: 0000000000000002 R14: ffff888139110000 R15: ffff888101901240 [ 3103.000790] FS: 00007f424cde4700(0000) GS:ffff88885f880000(0000) knlGS:0000000000000000 [ 3103.001486] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 3103.001986] CR2: 00007fd42e8dcb70 CR3: 000000011e68a003 CR4: 0000000000370ea0 [ 3103.002596] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 3103.003190] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 3103.003787] Call Trace: [ 3103.004055] <TASK> [ 3103.004297] ? __warn+0x7d/0x130 [ 3103.004623] ? __list_del_entry_valid_or_report+0x4f/0xc0 [ 3103.005094] ? report_bug+0xf1/0x1c0 [ 3103.005439] ? console_unlock+0x4a/0xd0 [ 3103.005806] ? handle_bug+0x3f/0x70 [ 3103.006149] ? exc_invalid_op+0x13/0x60 [ 3103.006531] ? asm_exc_invalid_op+0x16/0x20 [ 3103.007430] ? __list_del_entry_valid_or_report+0x4f/0xc0 [ 3103.007910] mlx5e_tc_del_fdb_peers_flow+0xcf/0x240 [mlx5_core] [ 3103.008463] mlx5e_tc_del_flow+0x46/0x270 [mlx5_core] [ 3103.008944] mlx5e_flow_put+0x26/0x50 [mlx5_core] [ 3103.009401] mlx5e_delete_flower+0x25f/0x380 [mlx5_core] [ 3103.009901] tc_setup_cb_destroy+0xab/0x180 [ 3103.010292] fl_hw_destroy_filter+0x99/0xc0 [cls_flower] [ 3103.010779] __fl_delete+0x2d4/0x2f0 [cls_flower] [ 3103.011207] fl_delete+0x36/0x80 [cls_flower] [ 3103.011614] tc_del_tfilter+0x56f/0x750 [ 3103.011982] rtnetlink_rcv_msg+0xff/0x3a0 [ 3103.012362] ? netlink_ack+0x1c7/0x4e0 [ 3103.012719] ? rtnl_calcit.isra.44+0x130/0x130 [ 3103.013134] netlink_rcv_skb+0x54/0x100 [ 3103.013533] netlink_unicast+0x1ca/0x2b0 [ 3103.013902] netlink_sendmsg+0x361/0x4d0 [ 3103.014269] __sock_sendmsg+0x38/0x60 [ 3103.014643] ____sys_sendmsg+0x1f2/0x200 [ 3103.015018] ? copy_msghdr_from_user+0x72/0xa0 [ 3103.015265] ___sys_sendmsg+0x87/0xd0 [ 3103.016608] ? copy_msghdr_from_user+0x72/0xa0 [ 3103.017014] ? ___sys_recvmsg+0x9b/0xd0 [ 3103.017381] ? ttwu_do_activate.isra.137+0x58/0x180 [ 3103.017821] ? wake_up_q+0x49/0x90 [ 3103.018157] ? futex_wake+0x137/0x160 [ 3103.018521] ? __sys_sendmsg+0x51/0x90 [ 3103.018882] __sys_sendmsg+0x51/0x90 [ 3103.019230] ? exit_to_user_mode_prepare+0x56/0x130 [ 3103.019670] do_syscall_64+0x3c/0x80 [ 3103.020017] entry_SYSCALL_64_after_hwframe+0x46/0xb0 [ 3103.020469] RIP: 0033:0x7f4254811ef4 [ 3103.020816] Code: 89 f3 48 83 ec 10 48 89 7c 24 08 48 89 14 24 e8 42 eb ff ff 48 8b 14 24 41 89 c0 48 89 de 48 8b 7c 24 08 b8 2e 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 30 44 89 c7 48 89 04 24 e8 78 eb ff ff 48 8b [ 3103.022290] RSP: 002b:00007f424cdd9480 EFLAGS: 00000293 ORIG_RAX: 000000000000002e [ 3103.022970] RAX: ffffffffffffffda RBX: 00007f424cdd9510 RCX: 00007f4254811ef4 [ 3103.023564] RDX: 0000000000000000 RSI: 00007f424cdd9510 RDI: 0000000000000012 [ 3103.024158] RBP: 00007f424cdda238 R08: 0000000000000000 R09: 00007f41d801a4b0 [ 3103.024748] R10: 0000000000000000 R11: 0000000000000293 R12: 0000000000000001 [ 3103.025341] R13: 00007f424cdd9510 R14: 00007f424cdda240 R15: 00007f424cdd99a0 [ 3103.025931] </TASK> [ 3103.026182] ---[ end trace 0000000000000000 ]--- [ 3103.027033] ------------[ cut here ]------------
--- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +2 -1
@@ -2014,9 +2014,10 @@ static void mlx5e_tc_del_fdb_peer_flow(struct mlx5e_tc_flow *flow,list_for_each_entry_safe (peer_flow, tmp, &flow->peer_flows, peer_flows) {if (peer_index !=mlx5_get_dev_index (peer_flow->priv->mdev))continue ; + +list_del (&peer_flow->peer_flows);if (refcount_dec_and_test (&peer_flow->refcnt)) {mlx5e_tc_del_fdb_flow (peer_flow->priv, peer_flow); -list_del (&peer_flow->peer_flows);kfree (peer_flow); } }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 189/346 net/mlx5: Fix a WARN upon a callback command failure
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yishai Hadas <[email protected]>
[ Upstream commit cc8091587779cfaddb6b29c9e9edb9079a282cad ]
The below WARN [1] is reported once a callback command failed.
As a callback runs under an interrupt context, needs to use the IRQ save/restore variant.
[1]
DEBUG_LOCKS_WARN_ON(lockdep_hardirq_context())
WARNING: CPU: 15 PID: 0 at kernel/locking/lockdep.c:4353
lockdep_hardirqs_on_prepare+0x11b/0x180
Modules linked in: vhost_net vhost tap mlx5_vfio_pcivfio_pci vfio_pci_core vfio_iommu_type1 vfio mlx5_vdpa vringh vhost_iotlb vdpa nfnetlink_cttimeout openvswitch nsh ip6table_mangle ip6table_nat ip6table_filter ip6_tables iptable_mangle xt_conntrackxt_MASQUERADE nf_conntrack_netlink nfnetlink xt_addrtype iptable_nat nf_nat br_netfilter rpcsec_gss_krb5 auth_rpcgss oid_registry overlay rpcrdma rdma_ucm ib_iser libiscsi scsi_transport_iscsi rdma_cm iw_cm ib_umad ib_ipoib ib_cm mlx5_ib ib_uverbs ib_core fuse mlx5_core
CPU: 15 PID: 0 Comm: swapper/15 Tainted: G W 6.7.0-rc4+ #1587
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS
rel-1.13.0-0-gf21b5a4aeb02-prebuilt.qemu.org 04/01/2014
RIP: 0010:lockdep_hardirqs_on_prepare+0x11b/0x180
Code: 00 5b c3 c3 e8 e6 0d 58 00 85 c0 74 d6 8b 15 f0 c3
76 01 85 d2 75 cc 48 c7 c6 04 a5 3b 82 48 c7 c7 f1
e9 39 82 e8 95 12 f9 ff <0f> 0b 5b c3 e8 bc 0d 58 00
85 c0 74 ac 8b 3d c6 c3 76 01 85 ff 75
RSP: 0018:ffffc900003ecd18 EFLAGS: 00010086
RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000027
RDX: 0000000000000000 RSI: ffff88885fbdb880 RDI: ffff88885fbdb888
RBP: 00000000ffffff87 R08: 0000000000000000 R09: 0000000000000001
R10: 0000000000000000 R11: 284e4f5f4e524157 R12: 00000000002c9aa1
R13: ffff88810aace980 R14: ffff88810aace9b8 R15: 0000000000000003
FS: 0000000000000000(0000) GS:ffff88885fbc0000(0000)
knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f731436f4c8 CR3: 000000010aae6001 CR4: 0000000000372eb0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
Call Trace:
<IRQ>
? __warn+0x81/0x170
? lockdep_hardirqs_on_prepare+0x11b/0x180
? report_bug+0xf8/0x1c0
? handle_bug+0x3f/0x70
? exc_invalid_op+0x13/0x60
? asm_exc_invalid_op+0x16/0x20
? lockdep_hardirqs_on_prepare+0x11b/0x180
? lockdep_hardirqs_on_prepare+0x11b/0x180
trace_hardirqs_on+0x4a/0xa0
raw_spin_unlock_irq+0x24/0x30
cmd_status_err+0xc0/0x1a0 [mlx5_core]
cmd_status_err+0x1a0/0x1a0 [mlx5_core]
mlx5_cmd_exec_cb_handler+0x24/0x40 [mlx5_core]
mlx5_cmd_comp_handler+0x129/0x4b0 [mlx5_core]
cmd_comp_notifier+0x1a/0x20 [mlx5_core]
notifier_call_chain+0x3e/0xe0
atomic_notifier_call_chain+0x5f/0x130
mlx5_eq_async_int+0xe7/0x200 [mlx5_core]
notifier_call_chain+0x3e/0xe0
atomic_notifier_call_chain+0x5f/0x130
irq_int_handler+0x11/0x20 [mlx5_core]
__handle_irq_event_percpu+0x99/0x220
? tick_irq_enter+0x5d/0x80
handle_irq_event_percpu+0xf/0x40
handle_irq_event+0x3a/0x60
handle_edge_irq+0xa2/0x1c0
__common_interrupt+0x55/0x140
common_interrupt+0x7d/0xa0
</IRQ>
<TASK>
asm_common_interrupt+0x22/0x40
RIP: 0010:default_idle+0x13/0x20
Code: c0 08 00 00 00 4d 29 c8 4c 01 c7 4c 29 c2 e9 72 ffff ff cc cc cc cc 8b 05 ea 08 25 01 85 c0 7e 07 0f 00 2d 7f b0 26 00 fb f4 <fa> c3 90 66 2e 0f 1f 84 00 00 00 00 00 65 48 8b 04 25 80 d0 02 00
RSP: 0018:ffffc9000010fec8 EFLAGS: 00000242
RAX: 0000000000000001 RBX: 000000000000000f RCX: 4000000000000000
RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffffffff811c410c
RBP: ffffffff829478c0 R08: 0000000000000001 R09: 0000000000000001
R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000
R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000
? do_idle+0x1ec/0x210 default_idle_call+0x6c/0x90 do_idle+0x1ec/0x210 cpu_startup_entry+0x26/0x30 start_secondary+0x11b/0x150 secondary_startup_64_no_verify+0x165/0x16b </TASK> irq event stamp: 833284 hardirqs last enabled at (833283): [<ffffffff811c410c>] do_idle+0x1ec/0x210 hardirqs last disabled at (833284): [<ffffffff81daf9ef>] common_interrupt+0xf/0xa0 softirqs last enabled at (833224): [<ffffffff81dc199f>] __do_softirq+0x2bf/0x40e softirqs last disabled at (833177): [<ffffffff81178ddf>] irq_exit_rcu+0x7f/0xa0
--- drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/cmd.c +3 -2
@@ -1923,6 +1923,7 @@ static void cmd_status_log(struct mlx5_core_dev *dev, u16 opcode, u8 status, {const char *namep =mlx5_command_str (opcode);struct mlx5_cmd_stats *stats; +unsigned long flags;if (!err || !(strcmp (namep,"unknown command opcode" )))return ;
@@ -1930,7 +1931,7 @@ static void cmd_status_log(struct mlx5_core_dev *dev, u16 opcode, u8 status, stats =xa_load (&dev->cmd.stats, opcode);if (!stats)return ; -spin_lock_irq (&stats->lock); +spin_lock_irqsave (&stats->lock, flags); stats->failed++;if (err <0 ) stats->last_failed_errno = -err;
@@ -1939,7 +1940,7 @@ static void cmd_status_log(struct mlx5_core_dev *dev, u16 opcode, u8 status, stats->last_failed_mbox_status = status; stats->last_failed_syndrome = syndrome; } -spin_unlock_irq (&stats->lock); +spin_unlock_irqrestore (&stats->lock, flags); }/* preserve -EREMOTEIO for outbox.status != OK, otherwise return err as is */
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 190/346 net/mlx5: Bridge, fix multicast packets sent to uplink
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Moshe Shemesh <[email protected]>
[ Upstream commit ec7cc38ef9f83553102e84c82536971a81630739 ]
To enable multicast packets which are offloaded in bridge multicast offload mode to be sent also to uplink, FTE bit uplink_hairpin_en should be set. Add this bit to FTE for the bridge multicast offload rules.
--- drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_mcast.c | 3 +++ drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c | 2 ++ include/linux/mlx5/fs.h | 1 + include/linux/mlx5/mlx5_ifc.h | 2 +- 4 files changed, 7 insertions(+), 1 deletion(-)
drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_mcast.c +3 -0
@@ -83,6 +83,7 @@ mlx5_esw_bridge_mdb_flow_create(u16 esw_owner_vhca_id, struct mlx5_esw_bridge_md i++; } + rule_spec->flow_context.flags |=FLOW_CONTEXT_UPLINK_HAIRPIN_EN ; rule_spec->match_criteria_enable =MLX5_MATCH_OUTER_HEADERS ; dmac_v =MLX5_ADDR_OF (fte_match_param, rule_spec->match_value, outer_headers.dmac_47_16);ether_addr_copy (dmac_v, entry->key.addr);
@@ -587,6 +588,7 @@ mlx5_esw_bridge_mcast_vlan_flow_create(u16 vlan_proto, struct mlx5_esw_bridge_poif (!rule_spec)return ERR_PTR (-ENOMEM ); + rule_spec->flow_context.flags |=FLOW_CONTEXT_UPLINK_HAIRPIN_EN ; rule_spec->match_criteria_enable =MLX5_MATCH_OUTER_HEADERS ; flow_act.action |=MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT ;
@@ -662,6 +664,7 @@ mlx5_esw_bridge_mcast_fwd_flow_create(struct mlx5_esw_bridge_port *port) dest.vport.flags =MLX5_FLOW_DEST_VPORT_VHCA_ID ; dest.vport.vhca_id = port->esw_owner_vhca_id; } + rule_spec->flow_context.flags |=FLOW_CONTEXT_UPLINK_HAIRPIN_EN ; handle =mlx5_add_flow_rules (port->mcast.ft, rule_spec, &flow_act, &dest,1 );kvfree (rule_spec);
drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c +2 -0
@@ -566,6 +566,8 @@ static int mlx5_cmd_set_fte(struct mlx5_core_dev *dev, fte->flow_context.flow_tag);MLX5_SET (flow_context, in_flow_context, flow_source, fte->flow_context.flow_source); +MLX5_SET (flow_context, in_flow_context, uplink_hairpin_en, + !!(fte->flow_context.flags &FLOW_CONTEXT_UPLINK_HAIRPIN_EN ));MLX5_SET (flow_context, in_flow_context, extended_destination, extended_dest);
include/linux/mlx5/fs.h +1 -0
@@ -132,6 +132,7 @@ struct mlx5_flow_handle;enum {FLOW_CONTEXT_HAS_TAG =BIT (0 ), +FLOW_CONTEXT_UPLINK_HAIRPIN_EN =BIT (1 ), };struct mlx5_flow_context {
include/linux/mlx5/mlx5_ifc.h +1 -1
@@ -3557,7 +3557,7 @@ struct mlx5_ifc_flow_context_bits {u8 action[0x10 ];u8 extended_destination[0x1 ]; -u8 reserved_at_81[0x1 ]; +u8 uplink_hairpin_en[0x1 ];u8 flow_source[0x2 ];u8 encrypt_decrypt_type[0x4 ];u8 destination_list_size[0x18 ];
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 191/346 net/mlx5: DR, Use the right GVMI number for drop action
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yevgeny Kliteynik <[email protected]>
[ Upstream commit 5665954293f13642f9c052ead83c1e9d8cff186f ]
When FW provides ICM addresses for drop RX/TX, the provided capability is 64 bits that contain its GVMI as well as the ICM address itself. In case of TX DROP this GVMI is different from the GVMI that the domain is operating on.
This patch fixes the action to use these GVMI IDs, as provided by FW.
--- drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c +1 -0
@@ -788,6 +788,7 @@ int mlx5dr_actions_build_ste_arr(struct mlx5dr_matcher *matcher,switch (action_type) {case DR_ACTION_TYP_DROP : attr.final_icm_addr = nic_dmn->drop_icm_addr; + attr.hit_gvmi = nic_dmn->drop_icm_addr >>48 ;break ;case DR_ACTION_TYP_FT : dest_action = action;
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 192/346 net/mlx5: DR, Cant go to uplink vport on RX rule
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yevgeny Kliteynik <[email protected]>
[ Upstream commit 5b2a2523eeea5f03d39a9d1ff1bad2e9f8eb98d2 ]
Go-To-Vport action on RX is not allowed when the vport is uplink. In such case, the packet should be dropped.
--- .../mellanox/mlx5/core/steering/dr_action.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c +11 -5
@@ -874,11 +874,17 @@ int mlx5dr_actions_build_ste_arr(struct mlx5dr_matcher *matcher, action->sampler->tx_icm_addr;break ;case DR_ACTION_TYP_VPORT : - attr.hit_gvmi = action->vport->caps->vhca_gvmi; - dest_action = action; - attr.final_icm_addr = rx_rule ? - action->vport->caps->icm_address_rx : - action->vport->caps->icm_address_tx; +if (unlikely (rx_rule && action->vport->caps->num ==MLX5_VPORT_UPLINK )) { +/* can't go to uplink on RX rule - dropping instead */ + attr.final_icm_addr = nic_dmn->drop_icm_addr; + attr.hit_gvmi = nic_dmn->drop_icm_addr >>48 ; + }else { + attr.hit_gvmi = action->vport->caps->vhca_gvmi; + dest_action = action; + attr.final_icm_addr = rx_rule ? + action->vport->caps->icm_address_rx : + action->vport->caps->icm_address_tx; + }break ;case DR_ACTION_TYP_POP_VLAN : if (!rx_rule && !(dmn->ste_ctx->actions_caps &
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 193/346 net/mlx5: Use mlx5 device constant for selecting CQ period mode for ASO
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rahul Rameshbabu <[email protected]>
[ Upstream commit 20cbf8cbb827094197f3b17db60d71449415db1e ]
mlx5 devices have specific constants for choosing the CQ period mode. These constants do not have to match the constants used by the kernel software API for DIM period mode selection.
--- drivers/net/ethernet/mellanox/mlx5/core/lib/aso.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/mellanox/mlx5/core/lib/aso.c +1 -1
@@ -98,7 +98,7 @@ static int create_aso_cq(struct mlx5_aso_cq *cq, void *cqc_data)mlx5_fill_page_frag_array (&cq->wq_ctrl.buf, (__be64 *)MLX5_ADDR_OF (create_cq_in, in, pas)); -MLX5_SET (cqc, cqc, cq_period_mode,DIM_CQ_PERIOD_MODE_START_FROM_EQE ); +MLX5_SET (cqc, cqc, cq_period_mode,MLX5_CQ_PERIOD_MODE_START_FROM_EQE );MLX5_SET (cqc, cqc, c_eqn_or_apu_element, eqn);MLX5_SET (cqc, cqc, uar_page, mdev->priv.uar->index); MLX5_SET(cqc, cqc, log_page_size, cq->wq_ctrl.buf.page_shift -
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 194/346 net/mlx5e: Allow software parsing when IPsec crypto is enabled
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Romanovsky <[email protected]>
[ Upstream commit 20f5468a7988dedd94a57ba8acd65ebda6a59723 ]
All ConnectX devices have software parsing capability enabled, but it is more correct to set allow_swp only if capability exists, which for IPsec means that crypto offload is supported.
--- drivers/net/ethernet/mellanox/mlx5/core/en/params.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/en/params.c +2 -2
@@ -1062,8 +1062,8 @@ void mlx5e_build_sq_param(struct mlx5_core_dev *mdev,void *wq =MLX5_ADDR_OF (sqc, sqc, wq);bool allow_swp; - allow_swp = -mlx5_geneve_tx_allowed (mdev) || !!mlx5_ipsec_device_caps (mdev); + allow_swp =mlx5_geneve_tx_allowed (mdev) || + (mlx5_ipsec_device_caps (mdev) &MLX5_IPSEC_CAP_CRYPTO );mlx5e_build_sq_param_common (mdev, param);MLX5_SET (wq, wq, log_wq_sz, params->log_sq_size);MLX5_SET (sqc, sqc, allow_swp, allow_swp);
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 195/346 net/mlx5e: Ignore IPsec replay window values on sender side
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Romanovsky <[email protected]>
[ Upstream commit 315a597f9bcfe7fe9980985031413457bee95510 ]
XFRM stack doesn't prevent from users to configure replay window in TX side and strongswan sets replay_window to be 1. It causes to failures in validation logic when trying to offload the SA.
Replay window is not relevant in TX side and should be ignored.
--- .../net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c +8 -2
@@ -336,12 +336,17 @@ void mlx5e_ipsec_build_accel_xfrm_attrs(struct mlx5e_ipsec_sa_entry *sa_entry,/* iv len */ aes_gcm->icv_len = x->aead->alg_icv_len; + attrs->dir = x->xso.dir; +/* esn */ if (x->props.flags &XFRM_STATE_ESN ) { attrs->replay_esn.trigger = true; attrs->replay_esn.esn = sa_entry->esn_state.esn; attrs->replay_esn.esn_msb = sa_entry->esn_state.esn_msb; attrs->replay_esn.overlap = sa_entry->esn_state.overlap; +if (attrs->dir ==XFRM_DEV_OFFLOAD_OUT ) + goto skip_replay_window; +switch (x->replay_esn->replay_window) {case 32 : attrs->replay_esn.replay_window =
@@ -365,7 +370,7 @@ void mlx5e_ipsec_build_accel_xfrm_attrs(struct mlx5e_ipsec_sa_entry *sa_entry, } } - attrs->dir = x->xso.dir; +skip_replay_window:/* spi */ attrs->spi =be32_to_cpu (x->id.spi);
@@ -501,7 +506,8 @@ static int mlx5e_xfrm_validate_state(struct mlx5_core_dev *mdev,return -EINVAL ; } -if (x->replay_esn && x->replay_esn->replay_window !=32 && +if (x->replay_esn && x->xso.dir ==XFRM_DEV_OFFLOAD_IN && + x->replay_esn->replay_window !=32 && x->replay_esn->replay_window !=64 && x->replay_esn->replay_window !=128 && x->replay_esn->replay_window !=256 ) {
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 196/346 net/mlx5e: fix a double-free in arfs_create_groups
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhipeng Lu <[email protected]>
[ Upstream commit 3c6d5189246f590e4e1f167991558bdb72a4738b ]
When in allocated by kvzalloc fails, arfs_create_groups will free ft->g and return an error. However, arfs_create_table, the only caller of arfs_create_groups, will hold this error and call to mlx5e_destroy_flow_table, in which the ft->g will be freed again.
--- .../net/ethernet/mellanox/mlx5/core/en_arfs.c | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c +15 -11
@@ -254,11 +254,13 @@ static int arfs_create_groups(struct mlx5e_flow_table *ft, ft->g =kcalloc (MLX5E_ARFS_NUM_GROUPS ,sizeof (*ft->g),GFP_KERNEL ); - in =kvzalloc (inlen,GFP_KERNEL ); -if (!in || !ft->g) { -kfree (ft->g); -kvfree (in); +if (!ft->g)return -ENOMEM ; + + in =kvzalloc (inlen,GFP_KERNEL ); +if (!in) { + err = -ENOMEM ; + goto err_free_g; } mc =MLX5_ADDR_OF (create_flow_group_in, in, match_criteria);
@@ -278,7 +280,7 @@ static int arfs_create_groups(struct mlx5e_flow_table *ft,break ;default : err = -EINVAL ; - goto out; + goto err_free_in; }switch (type) {
@@ -300,7 +302,7 @@ static int arfs_create_groups(struct mlx5e_flow_table *ft,break ;default : err = -EINVAL ; - goto out; + goto err_free_in; }MLX5_SET_CFG (in, match_criteria_enable,MLX5_MATCH_OUTER_HEADERS );
@@ -309,7 +311,7 @@ static int arfs_create_groups(struct mlx5e_flow_table *ft,MLX5_SET_CFG (in, end_flow_index, ix -1 ); ft->g[ft->num_groups] =mlx5_create_flow_group (ft->t, in);if (IS_ERR (ft->g[ft->num_groups])) - goto err; + goto err_clean_group; ft->num_groups++;memset (in,0 , inlen);
@@ -318,18 +320,20 @@ static int arfs_create_groups(struct mlx5e_flow_table *ft,MLX5_SET_CFG (in, end_flow_index, ix -1 ); ft->g[ft->num_groups] =mlx5_create_flow_group (ft->t, in);if (IS_ERR (ft->g[ft->num_groups])) - goto err; + goto err_clean_group; ft->num_groups++;kvfree (in);return 0 ; -err: +err_clean_group: err =PTR_ERR (ft->g[ft->num_groups]); ft->g[ft->num_groups] =NULL ; -out: +err_free_in:kvfree (in); - +err_free_g: +kfree (ft->g); + ft->g =NULL ;return err; }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 197/346 net/mlx5e: fix a potential double-free in fs_any_create_groups
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dinghao Liu <[email protected]>
[ Upstream commit aef855df7e1bbd5aa4484851561211500b22707e ]
When kcalloc() for ft->g succeeds but kvzalloc() for in fails, fs_any_create_groups() will free ft->g. However, its caller fs_any_create_table() will free ft->g again through calling mlx5e_destroy_flow_table(), which will lead to a double-free. Fix this by setting ft->g to NULL in fs_any_create_groups().
--- drivers/net/ethernet/mellanox/mlx5/core/en/fs_tt_redirect.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ethernet/mellanox/mlx5/core/en/fs_tt_redirect.c +1 -0
@@ -436,6 +436,7 @@ static int fs_any_create_groups(struct mlx5e_flow_table *ft) in =kvzalloc (inlen,GFP_KERNEL );if (!in || !ft->g) {kfree (ft->g); + ft->g =NULL ;kvfree (in);return -ENOMEM ; }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 198/346 rcu: Defer RCU kthreads wakeup when CPU is dying
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Frederic Weisbecker <[email protected]>
[ Upstream commit e787644caf7628ad3269c1fbd321c3255cf51710 ]
When the CPU goes idle for the last time during the CPU down hotplug process, RCU reports a final quiescent state for the current CPU. If this quiescent state propagates up to the top, some tasks may then be woken up to complete the grace period: the main grace period kthread and/or the expedited main workqueue (or kworker).
If those kthreads have a SCHED_FIFO policy, the wake up can indirectly arm the RT bandwith timer to the local offline CPU. Since this happens after hrtimers have been migrated at CPUHP_AP_HRTIMERS_DYING stage, the timer gets ignored. Therefore if the RCU kthreads are waiting for RT bandwidth to be available, they may never be actually scheduled.
This triggers TREE03 rcutorture hangs:
rcu: INFO: rcu_preempt self-detected stall on CPU rcu: 4-...!: (1 GPs behind) idle=9874/1/0x4000000000000000 softirq=0/0 fqs=20 rcuc=21071 jiffies(starved) rcu: (t=21035 jiffies g=938281 q=40787 ncpus=6) rcu: rcu_preempt kthread starved for 20964 jiffies! g938281 f0x0 RCU_GP_WAIT_FQS(5) ->state=0x0 ->cpu=0 rcu: Unless rcu_preempt kthread gets sufficient CPU time, OOM is now expected behavior. rcu: RCU grace-period kthread stack dump: task:rcu_preempt state:R running task stack:14896 pid:14 tgid:14 ppid:2 flags:0x00004000 Call Trace: <TASK> __schedule+0x2eb/0xa80 schedule+0x1f/0x90 schedule_timeout+0x163/0x270 ? __pfx_process_timeout+0x10/0x10 rcu_gp_fqs_loop+0x37c/0x5b0 ? __pfx_rcu_gp_kthread+0x10/0x10 rcu_gp_kthread+0x17c/0x200 kthread+0xde/0x110 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x2b/0x40 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1b/0x30 </TASK>
The situation can't be solved with just unpinning the timer. The hrtimer infrastructure and the nohz heuristics involved in finding the best remote target for an unpinned timer would then also need to handle enqueues from an offline CPU in the most horrendous way.
So fix this on the RCU side instead and defer the wake up to an online CPU if it's too late for the local one.
--- kernel/rcu/tree.c | 34 +++++++++++++++++++++++++++++++++- kernel/rcu/tree_exp.h | 3 +-- 2 files changed, 34 insertions(+), 3 deletions(-)
kernel/rcu/tree.c +33 -1
@@ -1013,6 +1013,38 @@ static bool rcu_future_gp_cleanup(struct rcu_node *rnp)return needmore; } +static void swake_up_one_online_ipi (void *arg) +{ +struct swait_queue_head *wqh = arg; + +swake_up_one (wqh); +} + +static void swake_up_one_online (struct swait_queue_head *wqh) +{ +int cpu =get_cpu (); + +/* +* If called from rcutree_report_cpu_starting(), wake up +* is dangerous that late in the CPU-down hotplug process. The +* scheduler might queue an ignored hrtimer. Defer the wake up +* to an online CPU instead. +*/ +if (unlikely (cpu_is_offline (cpu))) { +int target; + + target =cpumask_any_and (housekeeping_cpumask (HK_TYPE_RCU ), + cpu_online_mask); + +smp_call_function_single (target, swake_up_one_online_ipi, + wqh,0 ); +put_cpu (); + }else { +put_cpu (); +swake_up_one (wqh); + } +} +/* * Awaken the grace-period kthread. Don't do a self-awaken (unless in an * interrupt or softirq handler, in which case we just might immediately
@@ -1037,7 +1069,7 @@ static void rcu_gp_kthread_wake(void)return ;WRITE_ONCE (rcu_state.gp_wake_time, jiffies);WRITE_ONCE (rcu_state.gp_wake_seq,READ_ONCE (rcu_state.gp_seq)); -swake_up_one (&rcu_state.gp_wq); +swake_up_one_online (&rcu_state.gp_wq); }/*
kernel/rcu/tree_exp.h +1 -2
@@ -173,7 +173,6 @@ static bool sync_rcu_exp_done_unlocked(struct rcu_node *rnp)return ret; } -/* * Report the exit from RCU read-side critical section for the last task * that queued itself during or before the current expedited preemptible-RCU
@@ -201,7 +200,7 @@ static void __rcu_report_exp_rnp(struct rcu_node *rnp,raw_spin_unlock_irqrestore_rcu_node (rnp, flags);if (wake) {smp_mb ();/* EGP done before wake_up(). */ -swake_up_one (&rcu_state.expedited_wq); +swake_up_one_online (&rcu_state.expedited_wq); }break ; }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 199/346 netfilter: nft_limit: reject configurations that cause integer overflow
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit c9d9eb9c53d37cdebbad56b91e40baf42d5a97aa ]
Reject bogus configs where internal token counter wraps around. This only occurs with very very large requests, such as 17gbyte/s.
Its better to reject this rather than having incorrect ratelimit.
--- net/netfilter/nft_limit.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-)
net/netfilter/nft_limit.c +16 -7
@@ -58,17 +58,19 @@ static inline bool nft_limit_eval(struct nft_limit_priv *priv, u64 cost)static int nft_limit_init (struct nft_limit_priv *priv,const struct nlattr *const tb[],bool pkts) { +u64 unit, tokens, rate_with_burst;bool invert = false; -u64 unit, tokens;if (tb[NFTA_LIMIT_RATE ] ==NULL || tb[NFTA_LIMIT_UNIT ] ==NULL )return -EINVAL ; priv->rate =be64_to_cpu (nla_get_be64 (tb[NFTA_LIMIT_RATE ])); +if (priv->rate ==0 ) +return -EINVAL ; + unit =be64_to_cpu (nla_get_be64 (tb[NFTA_LIMIT_UNIT ])); - priv->nsecs = unit *NSEC_PER_SEC ; -if (priv->rate ==0 || priv->nsecs < unit) +if (check_mul_overflow (unit,NSEC_PER_SEC , &priv->nsecs))return -EOVERFLOW ;if (tb[NFTA_LIMIT_BURST ])
@@ -77,18 +79,25 @@ static int nft_limit_init(struct nft_limit_priv *priv,if (pkts && priv->burst ==0 ) priv->burst =NFT_LIMIT_PKT_BURST_DEFAULT ; -if (priv->rate + priv->burst < priv->rate) +if (check_add_overflow (priv->rate, priv->burst, &rate_with_burst))return -EOVERFLOW ;if (pkts) { - tokens =div64_u64 (priv->nsecs, priv->rate) * priv->burst; +u64 tmp =div64_u64 (priv->nsecs, priv->rate); + +if (check_mul_overflow (tmp, priv->burst, &tokens)) +return -EOVERFLOW ; }else { +u64 tmp; +/* The token bucket size limits the number of tokens can be * accumulated. tokens_max specifies the bucket size. * tokens_max = unit * (rate + burst) / rate. */ - tokens =div64_u64 (priv->nsecs * (priv->rate + priv->burst), - priv->rate); +if (check_mul_overflow (priv->nsecs, rate_with_burst, &tmp)) +return -EOVERFLOW ; + + tokens =div64_u64 (tmp, priv->rate); }if (tb[NFTA_LIMIT_FLAGS ]) {
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 200/346 netfilter: nf_tables: restrict anonymous set and map names to 16 bytes
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit b462579b2b86a8f5230543cadd3a4836be27baf7 ]
nftables has two types of sets/maps, one where userspace defines the name, and anonymous sets/maps, where userspace defines a template name.
For the latter, kernel requires presence of exactly one "%d". nftables uses "__set%d" and "__map%d" for this. The kernel will expand the format specifier and replaces it with the smallest unused number.
As-is, userspace could define a template name that allows to move the set name past the 256 bytes upperlimit (post-expansion).
I don't see how this could be a problem, but I would prefer if userspace cannot do this, so add a limit of 16 bytes for the '%d' template name.
16 bytes is the old total upper limit for set names that existed when nf_tables was merged initially.
--- net/netfilter/nf_tables_api.c | 4 ++++ 1 file changed, 4 insertions(+)
net/netfilter/nf_tables_api.c +4 -0
@@ -24,6 +24,7 @@#include <net/sock.h> #define NFT_MODULE_AUTOLOAD_LIMIT (MODULE_NAME_LEN - sizeof("nft-expr-255-")) +#define NFT_SET_MAX_ANONLEN 16unsigned int nf_tables_net_id__read_mostly ;
@@ -4411,6 +4412,9 @@ static int nf_tables_set_alloc_name(struct nft_ctx *ctx, struct nft_set *set,if (p[1 ] !='d' ||strchr (p +2 ,'%' ))return -EINVAL ; +if (strnlen (name,NFT_SET_MAX_ANONLEN ) >=NFT_SET_MAX_ANONLEN ) +return -EINVAL ; + inuse = (unsigned long *)get_zeroed_page (GFP_KERNEL );if (inuse ==NULL )return -ENOMEM ;
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 201/346 netfilter: nf_tables: validate NFPROTO_* family
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso <[email protected]>
[ Upstream commit d0009effa8862c20a13af4cb7475d9771b905693 ]
Several expressions explicitly refer to NF_INET_* hook definitions from expr->ops->validate, however, family is not validated.
Bail out with EOPNOTSUPP in case they are used from unsupported families.
--- net/netfilter/nft_compat.c | 12 ++++++++++++ net/netfilter/nft_flow_offload.c | 5 +++++ net/netfilter/nft_nat.c | 5 +++++ net/netfilter/nft_rt.c | 5 +++++ net/netfilter/nft_socket.c | 5 +++++ net/netfilter/nft_synproxy.c | 7 +++++-- net/netfilter/nft_tproxy.c | 5 +++++ net/netfilter/nft_xfrm.c | 5 +++++ 8 files changed, 47 insertions(+), 2 deletions(-)
net/netfilter/nft_compat.c +12 -0
@@ -350,6 +350,12 @@ static int nft_target_validate(const struct nft_ctx *ctx,unsigned int hook_mask =0 ;int ret; +if (ctx->family !=NFPROTO_IPV4 && + ctx->family !=NFPROTO_IPV6 && + ctx->family !=NFPROTO_BRIDGE && + ctx->family !=NFPROTO_ARP ) +return -EOPNOTSUPP ; +if (nft_is_base_chain (ctx->chain)) {const struct nft_base_chain *basechain =nft_base_chain (ctx->chain);
@@ -595,6 +601,12 @@ static int nft_match_validate(const struct nft_ctx *ctx,unsigned int hook_mask =0 ;int ret; +if (ctx->family !=NFPROTO_IPV4 && + ctx->family !=NFPROTO_IPV6 && + ctx->family !=NFPROTO_BRIDGE && + ctx->family !=NFPROTO_ARP ) +return -EOPNOTSUPP ; +if (nft_is_base_chain (ctx->chain)) {const struct nft_base_chain *basechain =nft_base_chain (ctx->chain);
net/netfilter/nft_flow_offload.c +5 -0
@@ -384,6 +384,11 @@ static int nft_flow_offload_validate(const struct nft_ctx *ctx, {unsigned int hook_mask = (1 <<NF_INET_FORWARD ); +if (ctx->family !=NFPROTO_IPV4 && + ctx->family !=NFPROTO_IPV6 && + ctx->family !=NFPROTO_INET ) +return -EOPNOTSUPP ; +return nft_chain_validate_hooks (ctx->chain, hook_mask); }
net/netfilter/nft_nat.c +5 -0
@@ -143,6 +143,11 @@ static int nft_nat_validate(const struct nft_ctx *ctx,struct nft_nat *priv =nft_expr_priv (expr);int err; +if (ctx->family !=NFPROTO_IPV4 && + ctx->family !=NFPROTO_IPV6 && + ctx->family !=NFPROTO_INET ) +return -EOPNOTSUPP ; + err =nft_chain_validate_dependency (ctx->chain,NFT_CHAIN_T_NAT );if (err <0 )return err;
net/netfilter/nft_rt.c +5 -0
@@ -166,6 +166,11 @@ static int nft_rt_validate(const struct nft_ctx *ctx, const struct nft_expr *expconst struct nft_rt *priv =nft_expr_priv (expr);unsigned int hooks; +if (ctx->family !=NFPROTO_IPV4 && + ctx->family !=NFPROTO_IPV6 && + ctx->family !=NFPROTO_INET ) +return -EOPNOTSUPP ; +switch (priv->key) {case NFT_RT_NEXTHOP4 :case NFT_RT_NEXTHOP6 :
net/netfilter/nft_socket.c +5 -0
@@ -242,6 +242,11 @@ static int nft_socket_validate(const struct nft_ctx *ctx,const struct nft_expr *expr, const struct nft_data **data) { + if (ctx->family != NFPROTO_IPV4 && + ctx->family != NFPROTO_IPV6 && + ctx->family != NFPROTO_INET) + return -EOPNOTSUPP; + return nft_chain_validate_hooks(ctx->chain, (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_IN) |
net/netfilter/nft_synproxy.c +5 -2
@@ -186,7 +186,6 @@ static int nft_synproxy_do_init(const struct nft_ctx *ctx,break ;#endif case NFPROTO_INET : -case NFPROTO_BRIDGE : err =nf_synproxy_ipv4_init (snet, ctx->net);if (err) goto nf_ct_failure;
@@ -219,7 +218,6 @@ static void nft_synproxy_do_destroy(const struct nft_ctx *ctx)break ;#endif case NFPROTO_INET : -case NFPROTO_BRIDGE :nf_synproxy_ipv4_fini (snet, ctx->net);nf_synproxy_ipv6_fini (snet, ctx->net);break ;
@@ -253,6 +251,11 @@ static int nft_synproxy_validate(const struct nft_ctx *ctx,const struct nft_expr *expr, const struct nft_data **data) { + if (ctx->family != NFPROTO_IPV4 && + ctx->family != NFPROTO_IPV6 && + ctx->family != NFPROTO_INET) + return -EOPNOTSUPP; + return nft_chain_validate_hooks(ctx->chain, (1 << NF_INET_LOCAL_IN) | (1 << NF_INET_FORWARD)); }
net/netfilter/nft_tproxy.c +5 -0
@@ -316,6 +316,11 @@ static int nft_tproxy_validate(const struct nft_ctx *ctx,const struct nft_expr *expr, const struct nft_data **data) { + if (ctx->family != NFPROTO_IPV4 && + ctx->family != NFPROTO_IPV6 && + ctx->family != NFPROTO_INET) + return -EOPNOTSUPP; + return nft_chain_validate_hooks(ctx->chain, 1 << NF_INET_PRE_ROUTING); }
net/netfilter/nft_xfrm.c +5 -0
@@ -235,6 +235,11 @@ static int nft_xfrm_validate(const struct nft_ctx *ctx, const struct nft_expr *econst struct nft_xfrm *priv =nft_expr_priv (expr);unsigned int hooks; +if (ctx->family !=NFPROTO_IPV4 && + ctx->family !=NFPROTO_IPV6 && + ctx->family !=NFPROTO_INET ) +return -EOPNOTSUPP ; +switch (priv->dir) {case XFRM_POLICY_IN : hooks = (1 << NF_INET_FORWARD) |
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 202/346 net: stmmac: Wait a bit for the reset to take effect
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bernd Edlinger <[email protected]>
[ Upstream commit a5f5eee282a0aae80227697e1d9c811b1726d31d ]
otherwise the synopsys_id value may be read out wrong, because the GMAC_VERSION register might still be in reset state, for at least 1 us after the reset is de-asserted.
Add a wait for 10 us before continuing to be on the safe side.
Quoted 1 line
From what have you got that delay value?
Just try and error, with very old linux versions and old gcc versions the synopsys_id was read out correctly most of the time (but not always), with recent linux versions and recnet gcc versions it was read out wrongly most of the time, but again not always.
I don't have access to the VHDL code in question, so I cannot tell why it takes so long to get the correct values, I also do not have more than a few hardware samples, so I cannot tell how long this timeout must be in worst case.
Experimentally I can tell that the register is read several times as zero immediately after the reset is de-asserted, also adding several no-ops is not enough, adding a printk is enough, also udelay(1) seems to be enough but I tried that not very often, and I have not access to many hardware samples to be 100% sure about the necessary delay. And since the udelay here is only executed once per device instance, it seems acceptable to delay the boot for 10 us.
BTW: my hardware's synopsys id is 0x37.
--- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +3 -0
@@ -7467,6 +7467,9 @@ int stmmac_dvr_probe(struct device *device,dev_err (priv->device,"unable to bring out of ahb reset: %pe\n" ,ERR_PTR (ret)); +/* Wait a bit for the reset to take effect */ +udelay (10 ); +/* Init MAC and get the capabilities */ ret =stmmac_hw_init (priv);if (ret)
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 203/346 net: mvpp2: clear BM pool before initialization
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jenishkumar Maheshbhai Patel <[email protected]>
[ Upstream commit 9f538b415db862e74b8c5d3abbccfc1b2b6caa38 ]
Register value persist after booting the kernel using kexec which results in kernel panic. Thus clear the BM pool registers before initialisation to fix the issue.
--- .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-)
drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +26 -1
@@ -614,12 +614,38 @@ static void mvpp23_bm_set_8pool_mode(struct mvpp2 *priv)mvpp2_write (priv,MVPP22_BM_POOL_BASE_ADDR_HIGH_REG , val); } +/* Cleanup pool before actual initialization in the OS */ +static void mvpp2_bm_pool_cleanup (struct mvpp2 *priv,int pool_id) +{ +unsigned int thread =mvpp2_cpu_to_thread (priv,get_cpu ()); +u32 val; +int i; + +/* Drain the BM from all possible residues left by firmware */ +for (i =0 ; i <MVPP2_BM_POOL_SIZE_MAX ; i++) +mvpp2_thread_read (priv, thread,MVPP2_BM_PHY_ALLOC_REG (pool_id)); + +put_cpu (); + +/* Stop the BM pool */ + val =mvpp2_read (priv,MVPP2_BM_POOL_CTRL_REG (pool_id)); + val |=MVPP2_BM_STOP_MASK ; +mvpp2_write (priv,MVPP2_BM_POOL_CTRL_REG (pool_id), val); +} +static int mvpp2_bm_init (struct device *dev,struct mvpp2 *priv) {enum dma_data_direction dma_dir =DMA_FROM_DEVICE ;int i, err, poolnum =MVPP2_BM_POOLS_NUM ;struct mvpp2_port *port; +if (priv->percpu_pools) + poolnum =mvpp2_get_nrxqs (priv) *2 ; + +/* Clean up the pool state in case it contains stale state */ +for (i =0 ; i < poolnum; i++) +mvpp2_bm_pool_cleanup (priv, i); +if (priv->percpu_pools) {for (i =0 ; i < priv->port_count; i++) { port = priv->port_list[i];
@@ -629,7 +655,6 @@ static int mvpp2_bm_init(struct device *dev, struct mvpp2 *priv) } } - poolnum =mvpp2_get_nrxqs (priv) *2 ;for (i =0 ; i < poolnum; i++) {/* the pool in use */ int pn = i / (poolnum /2 );
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 204/346 selftests: net: fix rps_default_mask with >32 CPUs
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jakub Kicinski <[email protected]>
[ Upstream commit 0719b5338a0cbe80d1637a5fb03d8141b5bfc7a1 ]
If there is more than 32 cpus the bitmask will start to contain commas, leading to:
./rps_default_mask.sh: line 36: [: 00000000,00000000: integer expression expected
Remove the commas, bash doesn't interpret leading zeroes as oct so that should be good enough. Switch to bash, Simon reports that not all shells support this type of substitution.
--- tools/testing/selftests/net/rps_default_mask.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
tools/testing/selftests/net/rps_default_mask.sh +5 -1
@@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # SPDX-License-Identifier: GPL-2.0 readonly ksft_skip=4
@@ -33,6 +33,10 @@ chk_rps() { rps_mask=$($cmd /sys/class/net/$dev_name/queues/rx-0/rps_cpus) printf "%-60s" "$msg" + + # In case there is more than 32 CPUs we need to remove commas from masks + rps_mask=${rps_mask//,} + expected_rps_mask=${expected_rps_mask//,} if [ $rps_mask -eq $expected_rps_mask ]; then echo "[ ok ]" else
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 205/346 selftests: netdevsim: fix the udp_tunnel_nic test
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jakub Kicinski <[email protected]>
[ Upstream commit 0879020a7817e7ce636372c016b4528f541c9f4d ]
This test is missing a whole bunch of checks for interface renaming and one ifup. Presumably it was only used on a system with renaming disabled and NetworkManager running.
--- .../selftests/drivers/net/netdevsim/udp_tunnel_nic.sh | 9 +++++++++ 1 file changed, 9 insertions(+)
tools/testing/selftests/drivers/net/netdevsim/udp_tunnel_nic.sh +9 -0
@@ -269,6 +269,7 @@ for port in 0 1; do echo 1 > $NSIM_DEV_SYS/new_port fi NSIM_NETDEV=`get_netdev_name old_netdevs` + ifconfig $NSIM_NETDEV up msg="new NIC device created" exp0=( 0 0 0 0 )
@@ -430,6 +431,7 @@ for port in 0 1; do fi echo $port > $NSIM_DEV_SYS/new_port + NSIM_NETDEV=`get_netdev_name old_netdevs` ifconfig $NSIM_NETDEV up overflow_table0 "overflow NIC table"
@@ -487,6 +489,7 @@ for port in 0 1; do fi echo $port > $NSIM_DEV_SYS/new_port + NSIM_NETDEV=`get_netdev_name old_netdevs` ifconfig $NSIM_NETDEV up overflow_table0 "overflow NIC table"
@@ -543,6 +546,7 @@ for port in 0 1; do fi echo $port > $NSIM_DEV_SYS/new_port + NSIM_NETDEV=`get_netdev_name old_netdevs` ifconfig $NSIM_NETDEV up overflow_table0 "destroy NIC"
@@ -572,6 +576,7 @@ for port in 0 1; do fi echo $port > $NSIM_DEV_SYS/new_port + NSIM_NETDEV=`get_netdev_name old_netdevs` ifconfig $NSIM_NETDEV up msg="create VxLANs v6"
@@ -632,6 +637,7 @@ for port in 0 1; do fi echo $port > $NSIM_DEV_SYS/new_port + NSIM_NETDEV=`get_netdev_name old_netdevs` ifconfig $NSIM_NETDEV up echo 110 > $NSIM_DEV_DFS/ports/$port/udp_ports_inject_error
@@ -687,6 +693,7 @@ for port in 0 1; do fi echo $port > $NSIM_DEV_SYS/new_port + NSIM_NETDEV=`get_netdev_name old_netdevs` ifconfig $NSIM_NETDEV up msg="create VxLANs v6"
@@ -746,6 +753,7 @@ for port in 0 1; do fi echo $port > $NSIM_DEV_SYS/new_port + NSIM_NETDEV=`get_netdev_name old_netdevs` ifconfig $NSIM_NETDEV up msg="create VxLANs v6"
@@ -876,6 +884,7 @@ msg="re-add a port" echo 2 > $NSIM_DEV_SYS/del_port echo 2 > $NSIM_DEV_SYS/new_port +NSIM_NETDEV=`get_netdev_name old_netdevs` check_tables msg="replace VxLAN in overflow table"
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 206/346 xsk: recycle buffer in case Rx queue was full
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maciej Fijalkowski <[email protected]>
[ Upstream commit 269009893146c495f41e9572dd9319e787c2eba9 ]
Add missing xsk_buff_free() call when __xsk_rcv_zc() failed to produce descriptor to XSK Rx queue.
--- net/xdp/xsk.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
net/xdp/xsk.c +8 -4
@@ -167,8 +167,10 @@ static int xsk_rcv_zc(struct xdp_sock *xs, struct xdp_buff *xdp, u32 len) contd =XDP_PKT_CONTD ; err =__xsk_rcv_zc (xs, xskb, len, contd); -if (err ||likely (!frags)) - goto out; +if (err) + goto err; +if (likely (!frags)) +return 0 ; xskb_list = &xskb->pool->xskb_list;list_for_each_entry_safe (pos, tmp, xskb_list, xskb_list_node) {
@@ -177,11 +179,13 @@ static int xsk_rcv_zc(struct xdp_sock *xs, struct xdp_buff *xdp, u32 len) len = pos->xdp.data_end - pos->xdp.data; err =__xsk_rcv_zc (xs, pos, len, contd);if (err) -return err; + goto err;list_del (&pos->xskb_list_node); } -out: +return 0 ; +err: +xsk_buff_free (xdp);return err; }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 207/346 xsk: make xsk_buff_pool responsible for clearing xdp_buff::flags
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maciej Fijalkowski <[email protected]>
[ Upstream commit f7f6aa8e24383fbb11ac55942e66da9660110f80 ]
XDP multi-buffer support introduced XDP_FLAGS_HAS_FRAGS flag that is used by drivers to notify data path whether xdp_buff contains fragments or not. Data path looks up mentioned flag on first buffer that occupies the linear part of xdp_buff, so drivers only modify it there. This is sufficient for SKB and XDP_DRV modes as usually xdp_buff is allocated on stack or it resides within struct representing driver's queue and fragments are carried via skb_frag_t structs. IOW, we are dealing with only one xdp_buff.
ZC mode though relies on list of xdp_buff structs that is carried via xsk_buff_pool::xskb_list, so ZC data path has to make sure that fragments do *not* have XDP_FLAGS_HAS_FRAGS set. Otherwise, xsk_buff_free() could misbehave if it would be executed against xdp_buff that carries a frag with XDP_FLAGS_HAS_FRAGS flag set. Such scenario can take place when within supplied XDP program bpf_xdp_adjust_tail() is used with negative offset that would in turn release the tail fragment from multi-buffer frame.
Calling xsk_buff_free() on tail fragment with XDP_FLAGS_HAS_FRAGS would result in releasing all the nodes from xskb_list that were produced by driver before XDP program execution, which is not what is intended - only tail fragment should be deleted from xskb_list and then it should be put onto xsk_buff_pool::free_list. Such multi-buffer frame will never make it up to user space, so from AF_XDP application POV there would be no traffic running, however due to free_list getting constantly new nodes, driver will be able to feed HW Rx queue with recycled buffers. Bottom line is that instead of traffic being redirected to user space, it would be continuously dropped.
To fix this, let us clear the mentioned flag on xsk_buff_pool side during xdp_buff initialization, which is what should have been done right from the start of XSK multi-buffer support.
--- drivers/net/ethernet/intel/i40e/i40e_xsk.c | 1 - drivers/net/ethernet/intel/ice/ice_xsk.c | 1 - include/net/xdp_sock_drv.h | 1 + net/xdp/xsk_buff_pool.c | 1 + 4 files changed, 2 insertions(+), 2 deletions(-)
drivers/net/ethernet/intel/i40e/i40e_xsk.c +0 -1
@@ -499,7 +499,6 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget) xdp_res =i40e_run_xdp_zc (rx_ring, first, xdp_prog);i40e_handle_xdp_result_zc (rx_ring, first, rx_desc, &rx_packets, &rx_bytes, xdp_res, &failure); - first->flags =0 ; next_to_clean = next_to_process;if (failure)break ;
drivers/net/ethernet/intel/ice/ice_xsk.c +0 -1
@@ -891,7 +891,6 @@ int ice_clean_rx_irq_zc(struct ice_rx_ring *rx_ring, int budget)if (!first) { first = xdp; -xdp_buff_clear_frags_flag (first); }else if (ice_add_xsk_frag (rx_ring, first, xdp, size)) {break ; }
include/net/xdp_sock_drv.h +1 -0
@@ -152,6 +152,7 @@ static inline void xsk_buff_set_size(struct xdp_buff *xdp, u32 size) xdp->data = xdp->data_hard_start +XDP_PACKET_HEADROOM ; xdp->data_meta = xdp->data; xdp->data_end = xdp->data + size; + xdp->flags =0 ; } static inline dma_addr_t xsk_buff_raw_get_dma(struct xsk_buff_pool *pool,
net/xdp/xsk_buff_pool.c +1 -0
@@ -541,6 +541,7 @@ struct xdp_buff *xp_alloc(struct xsk_buff_pool *pool) xskb->xdp.data = xskb->xdp.data_hard_start +XDP_PACKET_HEADROOM ; xskb->xdp.data_meta = xskb->xdp.data; + xskb->xdp.flags =0 ;if (pool->dma_need_sync) { dma_sync_single_range_for_device(pool->dev, xskb->dma, 0,
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 208/346 xsk: fix usage of multi-buffer BPF helpers for ZC XDP
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maciej Fijalkowski <[email protected]>
[ Upstream commit c5114710c8ce86b8317e9b448f4fd15c711c2a82 ]
Currently when packet is shrunk via bpf_xdp_adjust_tail() and memory type is set to MEM_TYPE_XSK_BUFF_POOL, null ptr dereference happens:
[1136314.192256] BUG: kernel NULL pointer dereference, address: 0000000000000034 [1136314.203943] #PF: supervisor read access in kernel mode [1136314.213768] #PF: error_code(0x0000) - not-present page [1136314.223550] PGD 0 P4D 0 [1136314.230684] Oops: 0000 [#1] PREEMPT SMP NOPTI [1136314.239621] CPU: 8 PID: 54203 Comm: xdpsock Not tainted 6.6.0+ #257 [1136314.250469] Hardware name: Intel Corporation S2600WFT/S2600WFT, BIOS SE5C620.86B.02.01.0008.031920191559 03/19/2019 [1136314.265615] RIP: 0010:__xdp_return+0x6c/0x210 [1136314.274653] Code: ad 00 48 8b 47 08 49 89 f8 a8 01 0f 85 9b 01 00 00 0f 1f 44 00 00 f0 41 ff 48 34 75 32 4c 89 c7 e9 79 cd 80 ff 83 fe 03 75 17 <f6> 41 34 01 0f 85 02 01 00 00 48 89 cf e9 22 cc 1e 00 e9 3d d2 86 [1136314.302907] RSP: 0018:ffffc900089f8db0 EFLAGS: 00010246 [1136314.312967] RAX: ffffc9003168aed0 RBX: ffff8881c3300000 RCX: 0000000000000000 [1136314.324953] RDX: 0000000000000000 RSI: 0000000000000003 RDI: ffffc9003168c000 [1136314.336929] RBP: 0000000000000ae0 R08: 0000000000000002 R09: 0000000000010000 [1136314.348844] R10: ffffc9000e495000 R11: 0000000000000040 R12: 0000000000000001 [1136314.360706] R13: 0000000000000524 R14: ffffc9003168aec0 R15: 0000000000000001 [1136314.373298] FS: 00007f8df8bbcb80(0000) GS:ffff8897e0e00000(0000) knlGS:0000000000000000 [1136314.386105] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [1136314.396532] CR2: 0000000000000034 CR3: 00000001aa912002 CR4: 00000000007706f0 [1136314.408377] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [1136314.420173] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [1136314.431890] PKRU: 55555554 [1136314.439143] Call Trace: [1136314.446058] <IRQ> [1136314.452465] ? __die+0x20/0x70 [1136314.459881] ? page_fault_oops+0x15b/0x440 [1136314.468305] ? exc_page_fault+0x6a/0x150 [1136314.476491] ? asm_exc_page_fault+0x22/0x30 [1136314.484927] ? __xdp_return+0x6c/0x210 [1136314.492863] bpf_xdp_adjust_tail+0x155/0x1d0 [1136314.501269] bpf_prog_ccc47ae29d3b6570_xdp_sock_prog+0x15/0x60 [1136314.511263] ice_clean_rx_irq_zc+0x206/0xc60 [ice] [1136314.520222] ? ice_xmit_zc+0x6e/0x150 [ice] [1136314.528506] ice_napi_poll+0x467/0x670 [ice] [1136314.536858] ? ttwu_do_activate.constprop.0+0x8f/0x1a0 [1136314.546010] __napi_poll+0x29/0x1b0 [1136314.553462] net_rx_action+0x133/0x270 [1136314.561619] __do_softirq+0xbe/0x28e [1136314.569303] do_softirq+0x3f/0x60
This comes from __xdp_return() call with xdp_buff argument passed as NULL which is supposed to be consumed by xsk_buff_free() call.
To address this properly, in ZC case, a node that represents the frag being removed has to be pulled out of xskb_list. Introduce appropriate xsk helpers to do such node operation and use them accordingly within bpf_xdp_adjust_tail().
--- include/net/xdp_sock_drv.h | 26 +++++++++++++++++++++++ net/core/filter.c | 42 ++++++++++++++++++++++++++++++++------ 2 files changed, 62 insertions(+), 6 deletions(-)
include/net/xdp_sock_drv.h +26 -0
@@ -147,6 +147,23 @@ static inline struct xdp_buff *xsk_buff_get_frag(struct xdp_buff *first)return ret; } +static inline void xsk_buff_del_tail (struct xdp_buff *tail) +{ + struct xdp_buff_xsk *xskb = container_of(tail, struct xdp_buff_xsk, xdp); + +list_del (&xskb->xskb_list_node); +} + +static inline struct xdp_buff *xsk_buff_get_tail (struct xdp_buff *first) +{ + struct xdp_buff_xsk *xskb = container_of(first, struct xdp_buff_xsk, xdp); +struct xdp_buff_xsk *frag; + + frag = list_last_entry(&xskb->pool->xskb_list, struct xdp_buff_xsk, + xskb_list_node); +return &frag->xdp; +} +static inline void xsk_buff_set_size (struct xdp_buff *xdp,u32 size) { xdp->data = xdp->data_hard_start +XDP_PACKET_HEADROOM ;
@@ -310,6 +327,15 @@ static inline struct xdp_buff *xsk_buff_get_frag(struct xdp_buff *first)return NULL ; } +static inline void xsk_buff_del_tail (struct xdp_buff *tail) +{ +} + +static inline struct xdp_buff *xsk_buff_get_tail (struct xdp_buff *first) +{ +return NULL ; +} +static inline void xsk_buff_set_size (struct xdp_buff *xdp,u32 size) { }
net/core/filter.c +36 -6
60 lines not on this page · raw message
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 209/346 ice: work on pre-XDP prog frag count
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maciej Fijalkowski <[email protected]>
[ Upstream commit ad2047cf5d9313200e308612aed516548873d124 ]
Fix an OOM panic in XDP_DRV mode when a XDP program shrinks a multi-buffer packet by 4k bytes and then redirects it to an AF_XDP socket.
Since support for handling multi-buffer frames was added to XDP, usage of bpf_xdp_adjust_tail() helper within XDP program can free the page that given fragment occupies and in turn decrease the fragment count within skb_shared_info that is embedded in xdp_buff struct. In current ice driver codebase, it can become problematic when page recycling logic decides not to reuse the page. In such case, __page_frag_cache_drain() is used with ice_rx_buf::pagecnt_bias that was not adjusted after refcount of page was changed by XDP prog which in turn does not drain the refcount to 0 and page is never freed.
To address this, let us store the count of frags before the XDP program was executed on Rx ring struct. This will be used to compare with current frag count from skb_shared_info embedded in xdp_buff. A smaller value in the latter indicates that XDP prog freed frag(s). Then, for given delta decrement pagecnt_bias for XDP_DROP verdict.
While at it, let us also handle the EOP frag within ice_set_rx_bufs_act() to make our life easier, so all of the adjustments needed to be applied against freed frags are performed in the single place.
--- drivers/net/ethernet/intel/ice/ice_txrx.c | 14 ++++++--- drivers/net/ethernet/intel/ice/ice_txrx.h | 1 + drivers/net/ethernet/intel/ice/ice_txrx_lib.h | 31 +++++++++++++------ 3 files changed, 32 insertions(+), 14 deletions(-)
drivers/net/ethernet/intel/ice/ice_txrx.c +9 -5
@@ -600,9 +600,7 @@ ice_run_xdp(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp, ret =ICE_XDP_CONSUMED ; } exit: - rx_buf->act = ret; -if (unlikely (xdp_buff_has_frags (xdp))) -ice_set_rx_bufs_act (xdp, rx_ring, ret); +ice_set_rx_bufs_act (xdp, rx_ring, ret); }/**
@@ -890,14 +888,17 @@ ice_add_xdp_frag(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp, }if (unlikely (sinfo->nr_frags ==MAX_SKB_FRAGS )) { -if (unlikely (xdp_buff_has_frags (xdp))) -ice_set_rx_bufs_act (xdp, rx_ring,ICE_XDP_CONSUMED ); +ice_set_rx_bufs_act (xdp, rx_ring,ICE_XDP_CONSUMED );return -ENOMEM ; }__skb_fill_page_desc_noacc (sinfo, sinfo->nr_frags++, rx_buf->page, rx_buf->page_offset, size); sinfo->xdp_frags_size += size; +/* remember frag count before XDP prog execution; bpf_xdp_adjust_tail() +* can pop off frags but driver has to handle it on its own +*/ + rx_ring->nr_frags = sinfo->nr_frags;if (page_is_pfmemalloc (rx_buf->page))xdp_buff_set_frag_pfmemalloc (xdp);
@@ -1249,6 +1250,7 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget) xdp->data =NULL ; rx_ring->first_desc = ntc; + rx_ring->nr_frags =0 ;continue ; construct_skb:if (likely (ice_ring_uses_build_skb (rx_ring)))
@@ -1264,10 +1266,12 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget) ICE_XDP_CONSUMED); xdp->data =NULL ; rx_ring->first_desc = ntc; + rx_ring->nr_frags =0 ;break ; } xdp->data =NULL ; rx_ring->first_desc = ntc; + rx_ring->nr_frags =0 ; stat_err_bits =BIT (ICE_RX_FLEX_DESC_STATUS0_RXE_S ); if (unlikely(ice_test_staterr(rx_desc->wb.status_error0,
drivers/net/ethernet/intel/ice/ice_txrx.h +1 -0
@@ -333,6 +333,7 @@ struct ice_rx_ring {struct ice_channel *ch;struct ice_tx_ring *xdp_ring;struct xsk_buff_pool *xsk_pool; +u32 nr_frags;dma_addr_t dma;/* physical address of ring */ u64 cached_phctime;u16 rx_buf_len;
drivers/net/ethernet/intel/ice/ice_txrx_lib.h +22 -9
@@ -12,26 +12,39 @@* act: action to store onto Rx buffers related to XDP buffer parts * * Set action that should be taken before putting Rx buffer from first frag -* to one before last. Last one is handled by caller of this function as it -* is the EOP frag that is currently being processed. This function is -* supposed to be called only when XDP buffer contains frags. +* to the last. */ static inline void ice_set_rx_bufs_act (struct xdp_buff *xdp,const struct ice_rx_ring *rx_ring,const unsigned int act) { -const struct skb_shared_info *sinfo =xdp_get_shared_info_from_buff (xdp); -u32 first = rx_ring->first_desc; -u32 nr_frags = sinfo->nr_frags; +u32 sinfo_frags =xdp_get_shared_info_from_buff (xdp)->nr_frags; +u32 nr_frags = rx_ring->nr_frags +1 ; +u32 idx = rx_ring->first_desc;u32 cnt = rx_ring->count;struct ice_rx_buf *buf;for (int i =0 ; i < nr_frags; i++) { - buf = &rx_ring->rx_buf[first]; + buf = &rx_ring->rx_buf[idx]; buf->act = act; -if (++first == cnt) - first =0 ; +if (++idx == cnt) + idx =0 ; + } + +/* adjust pagecnt_bias on frags freed by XDP prog */ +if (sinfo_frags < rx_ring->nr_frags && act ==ICE_XDP_CONSUMED ) { +u32 delta = rx_ring->nr_frags - sinfo_frags; + +while (delta) { +if (idx ==0 ) + idx = cnt -1 ; +else + idx--; + buf = &rx_ring->rx_buf[idx]; + buf->pagecnt_bias--; + delta--; + } } }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 210/346 i40e: handle multi-buffer packets that are shrunk by xdp prog
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tirthendu Sarkar <[email protected]>
[ Upstream commit 83014323c642b8faa2d64a5f303b41c019322478 ]
XDP programs can shrink packets by calling the bpf_xdp_adjust_tail() helper function. For multi-buffer packets this may lead to reduction of frag count stored in skb_shared_info area of the xdp_buff struct. This results in issues with the current handling of XDP_PASS and XDP_DROP cases.
For XDP_PASS, currently skb is being built using frag count of xdp_buffer before it was processed by XDP prog and thus will result in an inconsistent skb when frag count gets reduced by XDP prog. To fix this, get correct frag count while building the skb instead of using pre-obtained frag count.
For XDP_DROP, current page recycling logic will not reuse the page but instead will adjust the pagecnt_bias so that the page can be freed. This again results in inconsistent behavior as the page refcnt has already been changed by the helper while freeing the frag(s) as part of shrinking the packet. To fix this, only adjust pagecnt_bias for buffers that are stillpart of the packet post-xdp prog run.
--- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 40 ++++++++++++--------- 1 file changed, 23 insertions(+), 17 deletions(-)
drivers/net/ethernet/intel/i40e/i40e_txrx.c +23 -17
@@ -2099,7 +2099,8 @@ static void i40e_put_rx_buffer(struct i40e_ring *rx_ring,static void i40e_process_rx_buffs (struct i40e_ring *rx_ring,int xdp_res,struct xdp_buff *xdp) { -u32 next = rx_ring->next_to_clean; +u32 nr_frags =xdp_get_shared_info_from_buff (xdp)->nr_frags; +u32 next = rx_ring->next_to_clean, i =0 ;struct i40e_rx_buffer *rx_buffer; xdp->flags =0 ;
@@ -2112,10 +2113,10 @@ static void i40e_process_rx_buffs(struct i40e_ring *rx_ring, int xdp_res,if (!rx_buffer->page)continue ; -if (xdp_res ==I40E_XDP_CONSUMED ) - rx_buffer->pagecnt_bias++; -else +if (xdp_res !=I40E_XDP_CONSUMED )i40e_rx_buffer_flip (rx_buffer, xdp->frame_sz); +else if (i++ <= nr_frags) + rx_buffer->pagecnt_bias++;/* EOP buffer will be put in i40e_clean_rx_irq() */ if (next == rx_ring->next_to_process)
@@ -2129,20 +2130,20 @@ static void i40e_process_rx_buffs(struct i40e_ring *rx_ring, int xdp_res,* i40e_construct_skb - Allocate skb and populate it * @rx_ring: rx descriptor ring to transact packets on * @xdp: xdp_buff pointing to the data -* @nr_frags: number of buffers for the packet * * This function allocates an skb. It then populates it with the page * data from the current receive descriptor, taking care to set up the * skb correctly. */ static struct sk_buff *i40e_construct_skb (struct i40e_ring *rx_ring, -struct xdp_buff *xdp, -u32 nr_frags) +struct xdp_buff *xdp) {unsigned int size = xdp->data_end - xdp->data;struct i40e_rx_buffer *rx_buffer; +struct skb_shared_info *sinfo;unsigned int headlen;struct sk_buff *skb; +u32 nr_frags =0 ;/* prefetch first cache line of first page */ net_prefetch (xdp->data);
@@ -2180,6 +2181,10 @@ static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring,memcpy (__skb_put (skb, headlen), xdp->data,ALIGN (headlen,sizeof (long ))); +if (unlikely (xdp_buff_has_frags (xdp))) { + sinfo =xdp_get_shared_info_from_buff (xdp); + nr_frags = sinfo->nr_frags; + } rx_buffer =i40e_rx_bi (rx_ring, rx_ring->next_to_clean);/* update all of the pointers */ size -= headlen;
@@ -2199,9 +2204,8 @@ static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring, }if (unlikely (xdp_buff_has_frags (xdp))) { -struct skb_shared_info *sinfo, *skinfo =skb_shinfo (skb); +struct skb_shared_info *skinfo =skb_shinfo (skb); - sinfo =xdp_get_shared_info_from_buff (xdp);memcpy (&skinfo->frags[skinfo->nr_frags], &sinfo->frags[0 ],sizeof (skb_frag_t) * nr_frags);
@@ -2224,17 +2228,17 @@ static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring,* i40e_build_skb - Build skb around an existing buffer * @rx_ring: Rx descriptor ring to transact packets on * @xdp: xdp_buff pointing to the data -* @nr_frags: number of buffers for the packet * * This function builds an skb around an existing Rx buffer, taking care * to set up the skb correctly and avoid any memcpy overhead. */ static struct sk_buff *i40e_build_skb (struct i40e_ring *rx_ring, -struct xdp_buff *xdp, -u32 nr_frags) +struct xdp_buff *xdp) {unsigned int metasize = xdp->data - xdp->data_meta; +struct skb_shared_info *sinfo;struct sk_buff *skb; +u32 nr_frags;/* Prefetch first cache line of first page. If xdp->data_meta * is unused, this points exactly as xdp->data, otherwise we
@@ -2243,6 +2247,11 @@ static struct sk_buff *i40e_build_skb(struct i40e_ring *rx_ring,*/ net_prefetch (xdp->data_meta); +if (unlikely (xdp_buff_has_frags (xdp))) { + sinfo =xdp_get_shared_info_from_buff (xdp); + nr_frags = sinfo->nr_frags; + } +/* build an skb around the page buffer */ skb =napi_build_skb (xdp->data_hard_start, xdp->frame_sz);if (unlikely (!skb))
@@ -2255,9 +2264,6 @@ static struct sk_buff *i40e_build_skb(struct i40e_ring *rx_ring,skb_metadata_set (skb, metasize);if (unlikely (xdp_buff_has_frags (xdp))) { -struct skb_shared_info *sinfo; - - sinfo =xdp_get_shared_info_from_buff (xdp); xdp_update_skb_shared_info(skb, nr_frags, sinfo->xdp_frags_size, nr_frags * xdp->frame_sz,
@@ -2602,9 +2608,9 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget, total_rx_bytes += size; }else {if (ring_uses_build_skb (rx_ring)) - skb =i40e_build_skb (rx_ring, xdp, nfrags); + skb =i40e_build_skb (rx_ring, xdp);else - skb =i40e_construct_skb (rx_ring, xdp, nfrags); + skb =i40e_construct_skb (rx_ring, xdp);/* drop if we failed to retrieve a buffer */ if (!skb) {
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 211/346 ice: remove redundant xdp_rxq_info registration
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maciej Fijalkowski <[email protected]>
[ Upstream commit 2ee788c06493d02ee85855414cca39825e768aaf ]
xdp_rxq_info struct can be registered by drivers via two functions - xdp_rxq_info_reg() and __xdp_rxq_info_reg(). The latter one allows drivers that support XDP multi-buffer to set up xdp_rxq_info::frag_size which in turn will make it possible to grow the packet via bpf_xdp_adjust_tail() BPF helper.
Currently, ice registers xdp_rxq_info in two spots:
1) ice_setup_rx_ring() // via xdp_rxq_info_reg(), BUG
2) ice_vsi_cfg_rxq() // via __xdp_rxq_info_reg(), OK
Cited commit under fixes tag took care of setting up frag_size and updated registration scheme in 2) but it did not help as
1) is called before 2) and as shown above it uses old registration function. This means that 2) sees that xdp_rxq_info is already registered and never calls __xdp_rxq_info_reg() which leaves us with xdp_rxq_info::frag_size being set to 0.
To fix this misbehavior, simply remove xdp_rxq_info_reg() call from ice_setup_rx_ring().
--- drivers/net/ethernet/intel/ice/ice_txrx.c | 5 ----- 1 file changed, 5 deletions(-)
drivers/net/ethernet/intel/ice/ice_txrx.c +0 -5
@@ -513,11 +513,6 @@ int ice_setup_rx_ring(struct ice_rx_ring *rx_ring)if (ice_is_xdp_ena_vsi (rx_ring->vsi))WRITE_ONCE (rx_ring->xdp_prog, rx_ring->vsi->xdp_prog); -if (rx_ring->vsi->type ==ICE_VSI_PF && - !xdp_rxq_info_is_reg (&rx_ring->xdp_rxq)) -if (xdp_rxq_info_reg (&rx_ring->xdp_rxq, rx_ring->netdev, - rx_ring->q_index, rx_ring->q_vector->napi.napi_id)) - goto err;return 0 ; err:
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 212/346 intel: xsk: initialize skb_frag_t::bv_offset in ZC drivers
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maciej Fijalkowski <[email protected]>
[ Upstream commit 290779905d09d5fdf6caa4f58ddefc3f4db0c0a9 ]
Ice and i40e ZC drivers currently set offset of a frag within skb_shared_info to 0, which is incorrect. xdp_buffs that come from xsk_buff_pool always have 256 bytes of a headroom, so they need to be taken into account to retrieve xdp_buff::data via skb_frag_address(). Otherwise, bpf_xdp_frags_increase_tail() would be starting its job from xdp_buff::data_hard_start which would result in overwriting existing payload.
--- drivers/net/ethernet/intel/i40e/i40e_xsk.c | 3 ++- drivers/net/ethernet/intel/ice/ice_xsk.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-)
drivers/net/ethernet/intel/i40e/i40e_xsk.c +2 -1
@@ -414,7 +414,8 @@ i40e_add_xsk_frag(struct i40e_ring *rx_ring, struct xdp_buff *first, }__skb_fill_page_desc_noacc (sinfo, sinfo->nr_frags++, -virt_to_page (xdp->data_hard_start),0 , size); +virt_to_page (xdp->data_hard_start), +XDP_PACKET_HEADROOM , size); sinfo->xdp_frags_size += size;xsk_buff_add_frag (xdp);
drivers/net/ethernet/intel/ice/ice_xsk.c +2 -1
@@ -820,7 +820,8 @@ ice_add_xsk_frag(struct ice_rx_ring *rx_ring, struct xdp_buff *first, }__skb_fill_page_desc_noacc (sinfo, sinfo->nr_frags++, -virt_to_page (xdp->data_hard_start),0 , size); +virt_to_page (xdp->data_hard_start), +XDP_PACKET_HEADROOM , size); sinfo->xdp_frags_size += size;xsk_buff_add_frag (xdp);
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 213/346 ice: update xdp_rxq_info::frag_size for ZC enabled Rx queue
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maciej Fijalkowski <[email protected]>
[ Upstream commit 3de38c87174225487fc93befeea7d380db80aef6 ]
Now that ice driver correctly sets up frag_size in xdp_rxq_info, let us make it work for ZC multi-buffer as well. ice_rx_ring::rx_buf_len for ZC is being set via xsk_pool_get_rx_frame_size() and this needs to be propagated up to xdp_rxq_info.
Use a bigger hammer and instead of unregistering only xdp_rxq_info's memory model, unregister it altogether and register it again and have xdp_rxq_info with correct frag_size value.
--- drivers/net/ethernet/intel/ice/ice_base.c | 37 ++++++++++++++--------- 1 file changed, 23 insertions(+), 14 deletions(-)
drivers/net/ethernet/intel/ice/ice_base.c +23 -14
@@ -534,19 +534,27 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring) ring->rx_buf_len = ring->vsi->rx_buf_len;if (ring->vsi->type ==ICE_VSI_PF ) { -if (!xdp_rxq_info_is_reg (&ring->xdp_rxq)) -/* coverity[check_return] */ -__xdp_rxq_info_reg (&ring->xdp_rxq, ring->netdev, - ring->q_index, - ring->q_vector->napi.napi_id, - ring->vsi->rx_buf_len); +if (!xdp_rxq_info_is_reg (&ring->xdp_rxq)) { + err =__xdp_rxq_info_reg (&ring->xdp_rxq, ring->netdev, + ring->q_index, + ring->q_vector->napi.napi_id, + ring->rx_buf_len); +if (err) +return err; + } ring->xsk_pool =ice_xsk_pool (ring);if (ring->xsk_pool) { -xdp_rxq_info_unreg_mem_model (&ring->xdp_rxq); +xdp_rxq_info_unreg (&ring->xdp_rxq); ring->rx_buf_len =xsk_pool_get_rx_frame_size (ring->xsk_pool); + err =__xdp_rxq_info_reg (&ring->xdp_rxq, ring->netdev, + ring->q_index, + ring->q_vector->napi.napi_id, + ring->rx_buf_len); +if (err) +return err; err =xdp_rxq_info_reg_mem_model (&ring->xdp_rxq,MEM_TYPE_XSK_BUFF_POOL ,NULL );
@@ -557,13 +565,14 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)dev_info (dev,"Registered XDP mem model MEM_TYPE_XSK_BUFF_POOL on Rx ring %d\n" , ring->q_index); }else { -if (!xdp_rxq_info_is_reg (&ring->xdp_rxq)) -/* coverity[check_return] */ -__xdp_rxq_info_reg (&ring->xdp_rxq, - ring->netdev, - ring->q_index, - ring->q_vector->napi.napi_id, - ring->vsi->rx_buf_len); +if (!xdp_rxq_info_is_reg (&ring->xdp_rxq)) { + err =__xdp_rxq_info_reg (&ring->xdp_rxq, ring->netdev, + ring->q_index, + ring->q_vector->napi.napi_id, + ring->rx_buf_len); +if (err) +return err; + } err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq, MEM_TYPE_PAGE_SHARED,
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 214/346 xdp: reflect tail increase for MEM_TYPE_XSK_BUFF_POOL
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maciej Fijalkowski <[email protected]>
[ Upstream commit fbadd83a612c3b7aad2987893faca6bd24aaebb3 ]
XSK ZC Rx path calculates the size of data that will be posted to XSK Rx queue via subtracting xdp_buff::data_end from xdp_buff::data.
In bpf_xdp_frags_increase_tail(), when underlying memory type of xdp_rxq_info is MEM_TYPE_XSK_BUFF_POOL, add offset to data_end in tail fragment, so that later on user space will be able to take into account the amount of bytes added by XDP program.
--- net/core/filter.c | 2 ++ 1 file changed, 2 insertions(+)
net/core/filter.c +2 -0
@@ -4091,6 +4091,8 @@ static int bpf_xdp_frags_increase_tail(struct xdp_buff *xdp, int offset)memset (skb_frag_address (frag) +skb_frag_size (frag),0 , offset);skb_frag_size_add (frag, offset); sinfo->xdp_frags_size += offset; +if (rxq->mem.type ==MEM_TYPE_XSK_BUFF_POOL ) +xsk_buff_get_tail (xdp)->data_end += offset;return 0 ; }
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 215/346 i40e: set xdp_rxq_info::frag_size
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maciej Fijalkowski <[email protected]>
[ Upstream commit a045d2f2d03d23e7db6772dd83e0ba2705dfad93 ]
i40e support XDP multi-buffer so it is supposed to use __xdp_rxq_info_reg() instead of xdp_rxq_info_reg() and set the frag_size. It can not be simply converted at existing callsite because rx_buf_len could be un-initialized, so let us register xdp_rxq_info within i40e_configure_rx_ring(), which happen to be called with already initialized rx_buf_len value.
Commit 5180ff1364bc ("i40e: use int for i40e_status") converted 'err' to int, so two variables to deal with return codes are not needed within i40e_configure_rx_ring(). Remove 'ret' and use 'err' to handle status from xdp_rxq_info registration.
--- drivers/net/ethernet/intel/i40e/i40e_main.c | 40 ++++++++++++--------- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 9 ----- 2 files changed, 24 insertions(+), 25 deletions(-)
drivers/net/ethernet/intel/i40e/i40e_main.c +24 -16
@@ -3588,40 +3588,48 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)struct i40e_hmc_obj_rxq rx_ctx;int err =0 ;bool ok; -int ret;bitmap_zero (ring->state, __I40E_RING_STATE_NBITS);/* clear the context structure first */ memset (&rx_ctx,0 ,sizeof (rx_ctx)); -if (ring->vsi->type ==I40E_VSI_MAIN ) -xdp_rxq_info_unreg_mem_model (&ring->xdp_rxq); + ring->rx_buf_len = vsi->rx_buf_len; + +/* XDP RX-queue info only needed for RX rings exposed to XDP */ +if (ring->vsi->type !=I40E_VSI_MAIN ) + goto skip; + +if (!xdp_rxq_info_is_reg (&ring->xdp_rxq)) { + err =__xdp_rxq_info_reg (&ring->xdp_rxq, ring->netdev, + ring->queue_index, + ring->q_vector->napi.napi_id, + ring->rx_buf_len); +if (err) +return err; + } ring->xsk_pool =i40e_xsk_pool (ring);if (ring->xsk_pool) { - ring->rx_buf_len = -xsk_pool_get_rx_frame_size (ring->xsk_pool); - ret =xdp_rxq_info_reg_mem_model (&ring->xdp_rxq, + ring->rx_buf_len =xsk_pool_get_rx_frame_size (ring->xsk_pool); + err =xdp_rxq_info_reg_mem_model (&ring->xdp_rxq,MEM_TYPE_XSK_BUFF_POOL ,NULL ); -if (ret) -return ret; +if (err) +return err;dev_info (&vsi->back->pdev->dev,"Registered XDP mem model MEM_TYPE_XSK_BUFF_POOL on Rx ring %d\n" , ring->queue_index); }else { - ring->rx_buf_len = vsi->rx_buf_len; -if (ring->vsi->type ==I40E_VSI_MAIN ) { - ret =xdp_rxq_info_reg_mem_model (&ring->xdp_rxq, -MEM_TYPE_PAGE_SHARED , -NULL ); -if (ret) -return ret; - } + err =xdp_rxq_info_reg_mem_model (&ring->xdp_rxq, +MEM_TYPE_PAGE_SHARED , +NULL ); +if (err) +return err; } +skip:xdp_init_buff (&ring->xdp,i40e_rx_pg_size (ring) /2 , &ring->xdp_rxq); rx_ctx.dbuff = DIV_ROUND_UP(ring->rx_buf_len,
drivers/net/ethernet/intel/i40e/i40e_txrx.c +0 -9
@@ -1555,7 +1555,6 @@ void i40e_free_rx_resources(struct i40e_ring *rx_ring)int i40e_setup_rx_descriptors (struct i40e_ring *rx_ring) {struct device *dev = rx_ring->dev; -int err;u64_stats_init (&rx_ring->syncp);
@@ -1576,14 +1575,6 @@ int i40e_setup_rx_descriptors(struct i40e_ring *rx_ring) rx_ring->next_to_process =0 ; rx_ring->next_to_use =0 ; -/* XDP RX-queue info only needed for RX rings exposed to XDP */ -if (rx_ring->vsi->type ==I40E_VSI_MAIN ) { - err =xdp_rxq_info_reg (&rx_ring->xdp_rxq, rx_ring->netdev, - rx_ring->queue_index, rx_ring->q_vector->napi.napi_id); -if (err <0 ) -return err; - } - rx_ring->xdp_prog = rx_ring->vsi->xdp_prog; rx_ring->rx_bi =
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 216/346 i40e: update xdp_rxq_info::frag_size for ZC enabled Rx queue
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maciej Fijalkowski <[email protected]>
[ Upstream commit 0cbb08707c932b3f004bc1a8ec6200ef572c1f5f ]
Now that i40e driver correctly sets up frag_size in xdp_rxq_info, let us make it work for ZC multi-buffer as well. i40e_ring::rx_buf_len for ZC is being set via xsk_pool_get_rx_frame_size() and this needs to be propagated up to xdp_rxq_info.
--- drivers/net/ethernet/intel/i40e/i40e_main.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/net/ethernet/intel/i40e/i40e_main.c +7 -0
@@ -3611,7 +3611,14 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring) ring->xsk_pool =i40e_xsk_pool (ring);if (ring->xsk_pool) { +xdp_rxq_info_unreg (&ring->xdp_rxq); ring->rx_buf_len =xsk_pool_get_rx_frame_size (ring->xsk_pool); + err =__xdp_rxq_info_reg (&ring->xdp_rxq, ring->netdev, + ring->queue_index, + ring->q_vector->napi.napi_id, + ring->rx_buf_len); +if (err) +return err; err =xdp_rxq_info_reg_mem_model (&ring->xdp_rxq,MEM_TYPE_XSK_BUFF_POOL ,NULL );
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 217/346 fjes: fix memleaks in fjes_hw_setup
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhipeng Lu <[email protected]>
[ Upstream commit f6cc4b6a3ae53df425771000e9c9540cce9b7bb1 ]
In fjes_hw_setup, it allocates several memory and delay the deallocation to the fjes_hw_exit in fjes_probe through the following call chain:
fjes_probe
|-> fjes_hw_init
|-> fjes_hw_setup
|-> fjes_hw_exit
However, when fjes_hw_setup fails, fjes_hw_exit won't be called and thus all the resources allocated in fjes_hw_setup will be leaked. In this patch, we free those resources in fjes_hw_setup and prevents such leaks.
--- drivers/net/fjes/fjes_hw.c | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-)
drivers/net/fjes/fjes_hw.c +30 -7
@@ -221,21 +221,25 @@ static int fjes_hw_setup(struct fjes_hw *hw) mem_size =FJES_DEV_REQ_BUF_SIZE (hw->max_epid); hw->hw_info.req_buf =kzalloc (mem_size,GFP_KERNEL ); -if (!(hw->hw_info.req_buf)) -return -ENOMEM ; +if (!(hw->hw_info.req_buf)) { + result = -ENOMEM ; + goto free_ep_info; + } hw->hw_info.req_buf_size = mem_size; mem_size =FJES_DEV_RES_BUF_SIZE (hw->max_epid); hw->hw_info.res_buf =kzalloc (mem_size,GFP_KERNEL ); -if (!(hw->hw_info.res_buf)) -return -ENOMEM ; +if (!(hw->hw_info.res_buf)) { + result = -ENOMEM ; + goto free_req_buf; + } hw->hw_info.res_buf_size = mem_size; result =fjes_hw_alloc_shared_status_region (hw);if (result) -return result; + goto free_res_buf; hw->hw_info.buffer_share_bit =0 ; hw->hw_info.buffer_unshare_reserve_bit =0 ;
@@ -246,11 +250,11 @@ static int fjes_hw_setup(struct fjes_hw *hw) result =fjes_hw_alloc_epbuf (&buf_pair->tx);if (result) -return result; + goto free_epbuf; result =fjes_hw_alloc_epbuf (&buf_pair->rx);if (result) -return result; + goto free_epbuf;spin_lock_irqsave (&hw->rx_status_lock, flags); fjes_hw_setup_epbuf(&buf_pair->tx, mac,
@@ -273,6 +277,25 @@ static int fjes_hw_setup(struct fjes_hw *hw)fjes_hw_init_command_registers (hw, ¶m);return 0 ; + +free_epbuf: +for (epidx =0 ; epidx < hw->max_epid ; epidx++) { +if (epidx == hw->my_epid) +continue ; +fjes_hw_free_epbuf (&hw->ep_shm_info[epidx].tx); +fjes_hw_free_epbuf (&hw->ep_shm_info[epidx].rx); + } +fjes_hw_free_shared_status_region (hw); +free_res_buf: +kfree (hw->hw_info.res_buf); + hw->hw_info.res_buf =NULL ; +free_req_buf: +kfree (hw->hw_info.req_buf); + hw->hw_info.req_buf =NULL ; +free_ep_info: +kfree (hw->ep_shm_info); + hw->ep_shm_info =NULL ; +return result; }static void fjes_hw_cleanup (struct fjes_hw *hw)
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 218/346 selftests: bonding: do not test arp/ns target with mode balance-alb/tlb
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hangbin Liu <[email protected]>
[ Upstream commit a2933a8759a62269754e54733d993b19de870e84 ]
The prio_arp/ns tests hard code the mode to active-backup. At the same time, The balance-alb/tlb modes do not support arp/ns target. So remove the prio_arp/ns tests from the loop and only test active-backup mode.
--- .../testing/selftests/drivers/net/bonding/bond_options.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
tools/testing/selftests/drivers/net/bonding/bond_options.sh +4 -4
@@ -162,7 +162,7 @@ prio_arp() local mode=$1 for primary_reselect in 0 1 2; do - prio_test "mode active-backup arp_interval 100 arp_ip_target ${g_ip4} primary eth1 primary_reselect $primary_reselect" + prio_test "mode $mode arp_interval 100 arp_ip_target ${g_ip4} primary eth1 primary_reselect $primary_reselect" log_test "prio" "$mode arp_ip_target primary_reselect $primary_reselect" done }
@@ -178,7 +178,7 @@ prio_ns() fi for primary_reselect in 0 1 2; do - prio_test "mode active-backup arp_interval 100 ns_ip6_target ${g_ip6} primary eth1 primary_reselect $primary_reselect" + prio_test "mode $mode arp_interval 100 ns_ip6_target ${g_ip6} primary eth1 primary_reselect $primary_reselect" log_test "prio" "$mode ns_ip6_target primary_reselect $primary_reselect" done }
@@ -194,9 +194,9 @@ prio() for mode in $modes; do prio_miimon $mode - prio_arp $mode - prio_ns $mode done + prio_arp "active-backup" + prio_ns "active-backup" } arp_validate_test()
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 219/346 net: fec: fix the unhandled context fault from smmu
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shenwei Wang <[email protected]>
[ Upstream commit 5e344807735023cd3a67c37a1852b849caa42620 ]
When repeatedly changing the interface link speed using the command below:
ethtool -s eth0 speed 100 duplex full
ethtool -s eth0 speed 1000 duplex full
The following errors may sometimes be reported by the ARM SMMU driver:
[ 5395.035364] fec 5b040000.ethernet eth0: Link is Down [ 5395.039255] arm-smmu 51400000.iommu: Unhandled context fault: fsr=0x402, iova=0x00000000, fsynr=0x100001, cbfrsynra=0x852, cb=2 [ 5398.108460] fec 5b040000.ethernet eth0: Link is Up - 100Mbps/Full -
flow control off
It is identified that the FEC driver does not properly stop the TX queue during the link speed transitions, and this results in the invalid virtual I/O address translations from the SMMU and causes the context faults.
--- drivers/net/ethernet/freescale/fec_main.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/ethernet/freescale/fec_main.c +2 -0
@@ -2036,6 +2036,7 @@ static void fec_enet_adjust_link(struct net_device *ndev)/* if any of the above changed restart the FEC */ if (status_change) { +netif_stop_queue (ndev);napi_disable (&fep->napi);netif_tx_lock_bh (ndev);fec_restart (ndev);
@@ -2045,6 +2046,7 @@ static void fec_enet_adjust_link(struct net_device *ndev) } }else {if (fep->link) { +netif_stop_queue (ndev);napi_disable (&fep->napi);netif_tx_lock_bh (ndev);fec_stop (ndev);
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 220/346 tsnep: Remove FCS for XDP data path
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gerhard Engleder <[email protected]>
[ Upstream commit 50bad6f797d4d501c5ef416a6f92e1912ab5aa8b ]
The RX data buffer includes the FCS. The FCS is already stripped for the normal data path. But for the XDP data path the FCS is included and acts like additional/useless data.
Remove the FCS from the RX data buffer also for XDP.
--- drivers/net/ethernet/engleder/tsnep_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/ethernet/engleder/tsnep_main.c +2 -2
@@ -1485,7 +1485,7 @@ static int tsnep_rx_poll(struct tsnep_rx *rx, struct napi_struct *napi,xdp_prepare_buff (&xdp,page_address (entry->page),XDP_PACKET_HEADROOM +TSNEP_RX_INLINE_METADATA_SIZE , - length, false); + length -ETH_FCS_LEN , false); consume =tsnep_xdp_run_prog (rx, prog, &xdp, &xdp_status, tx_nq, tx);
@@ -1568,7 +1568,7 @@ static int tsnep_rx_poll_zc(struct tsnep_rx *rx, struct napi_struct *napi,prefetch (entry->xdp->data); length =__le32_to_cpu (entry->desc_wb->properties) &TSNEP_DESC_LENGTH_MASK ; -xsk_buff_set_size (entry->xdp, length); +xsk_buff_set_size (entry->xdp, length -ETH_FCS_LEN );xsk_buff_dma_sync_for_cpu (entry->xdp, rx->xsk_pool);/* RX metadata with timestamps is in front of actual data,
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 221/346 tsnep: Fix XDP_RING_NEED_WAKEUP for empty fill ring
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gerhard Engleder <[email protected]>
[ Upstream commit 9a91c05f4bd6f6bdd6b8f90445e0da92e3ac956c ]
The fill ring of the XDP socket may contain not enough buffers to completey fill the RX queue during socket creation. In this case the flag XDP_RING_NEED_WAKEUP is not set as this flag is only set if the RX queue is not completely filled during polling.
Set XDP_RING_NEED_WAKEUP flag also if RX queue is not completely filled during XDP socket creation.
--- drivers/net/ethernet/engleder/tsnep_main.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
drivers/net/ethernet/engleder/tsnep_main.c +13 -0
@@ -1762,6 +1762,19 @@ static void tsnep_rx_reopen_xsk(struct tsnep_rx *rx) allocated--; } } + +/* set need wakeup flag immediately if ring is not filled completely, +* first polling would be too late as need wakeup signalisation would +* be delayed for an indefinite time +*/ +if (xsk_uses_need_wakeup (rx->xsk_pool)) { +int desc_available =tsnep_rx_desc_available (rx); + +if (desc_available) +xsk_set_rx_need_wakeup (rx->xsk_pool); +else +xsk_clear_rx_need_wakeup (rx->xsk_pool); + } }static bool tsnep_pending (struct tsnep_queue *queue)
Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerPATCH 222/346 btrfs: zoned: fix lock ordering in btrfs_zone_activate()
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Naohiro Aota <[email protected]>
commit b18f3b60b35a8c01c9a2a0f0d6424c6d73971dc3 upstream.
The btrfs CI reported a lockdep warning as follows by running generic generic/129.
WARNING: possible circular locking dependency detected
6.7.0-rc5+ #1 Not tainted
------------------------------------------------------
kworker/u5:5/793427 is trying to acquire lock:
ffff88813256d028 (&cache->lock){+.+.}-{2:2}, at: btrfs_zone_finish_one_bg+0x5e/0x130 but task is already holding lock:
ffff88810a23a318 (&fs_info->zone_active_bgs_lock){+.+.}-{2:2}, at: btrfs_zone_finish_one_bg+0x34/0x130 which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #1 (&fs_info->zone_active_bgs_lock){+.+.}-{2:2}:
...
-> #0 (&cache->lock){+.+.}-{2:2}:
...
This is because we take fs_info->zone_active_bgs_lock after a block_group's lock in btrfs_zone_activate() while doing the opposite in other places.
Fix the issue by expanding the fs_info->zone_active_bgs_lock's critical section and taking it before a block_group's lock.
--- fs/btrfs/zoned.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-)
fs/btrfs/zoned.c +2 -6
@@ -2094,6 +2094,7 @@ bool btrfs_zone_activate(struct btrfs_bl map = block_group->physical_map; +spin_lock (&fs_info->zone_active_bgs_lock);spin_lock (&block_group->lock);if (test_bit (BLOCK_GROUP_FLAG_ZONE_IS_ACTIVE , &block_group->runtime_flags)) { ret = true;
@@ -2106,7 +2107,6 @@ bool btrfs_zone_activate(struct btrfs_bl goto out_unlock; } -spin_lock (&fs_info->zone_active_bgs_lock);for (i =0 ; i < map->num_stripes; i++) {struct btrfs_zoned_device_info *zinfo;int reserved =0 ;
@@ -2126,20 +2126,17 @@ bool btrfs_zone_activate(struct btrfs_bl*/ if (atomic_read (&zinfo->active_zones_left) <= reserved) { ret = false; -spin_unlock (&fs_info->zone_active_bgs_lock); goto out_unlock; }if (!btrfs_dev_set_active_zone (device, physical)) {/* Cannot activate the zone */ ret = false; -spin_unlock (&fs_info->zone_active_bgs_lock); goto out_unlock; }if (!is_data) zinfo->reserved_active_zones--; } -spin_unlock (&fs_info->zone_active_bgs_lock);/* Successfully activated all the zones */ set_bit (BLOCK_GROUP_FLAG_ZONE_IS_ACTIVE , &block_group->runtime_flags);
@@ -2147,8 +2144,6 @@ bool btrfs_zone_activate(struct btrfs_bl/* For the active block group list */ btrfs_get_block_group (block_group); - -spin_lock (&fs_info->zone_active_bgs_lock);list_add_tail (&block_group->active_bg_list, &fs_info->zone_active_bgs);spin_unlock (&fs_info->zone_active_bgs_lock);
@@ -2156,6 +2151,7 @@ bool btrfs_zone_activate(struct btrfs_bl out_unlock:spin_unlock (&block_group->lock); +spin_unlock (&fs_info->zone_active_bgs_lock);return ret; }
Greg Kroah-Hartman
maintainerPATCH 223/346 btrfs: avoid copying BTRFS_ROOT_SUBVOL_DEAD flag to snapshot of subvolume being deleted
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Omar Sandoval <[email protected]>
commit 3324d0547861b16cf436d54abba7052e0c8aa9de upstream.
Sweet Tea spotted a race between subvolume deletion and snapshotting that can result in the root item for the snapshot having the BTRFS_ROOT_SUBVOL_DEAD flag set. The race is:
Thread 1 | Thread 2
----------------------------------------------|----------
btrfs_delete_subvolume |
btrfs_set_root_flags(BTRFS_ROOT_SUBVOL_DEAD)|
|btrfs_mksubvol
| down_read(subvol_sem)
| create_snapshot
| ...
| create_pending_snapshot
| copy root item from source
down_write(subvol_sem) |This flag is only checked in send and swap activate, which this would cause to fail mysteriously.
create_snapshot() now checks the root refs to reject a deleted subvolume, so we can fix this by locking subvol_sem earlier so that the BTRFS_ROOT_SUBVOL_DEAD flag and the root refs are updated atomically.
--- fs/btrfs/inode.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-)
fs/btrfs/inode.c +13 -9
@@ -4449,6 +4449,8 @@ int btrfs_delete_subvolume(struct btrfs_u64 root_flags;int ret; +down_write (&fs_info->subvol_sem); +/* * Don't allow to delete a subvolume with send in progress. This is * inside the inode lock so the error handling that has to drop the bit
@@ -4460,25 +4462,25 @@ int btrfs_delete_subvolume(struct btrfs_btrfs_warn (fs_info,"attempt to delete subvolume %llu during send" , dest->root_key.objectid); -return -EPERM ; + ret = -EPERM ; + goto out_up_write; }if (atomic_read (&dest->nr_swapfiles)) {spin_unlock (&dest->root_item_lock);btrfs_warn (fs_info,"attempt to delete subvolume %llu with active swapfile" , root->root_key.objectid); -return -EPERM ; + ret = -EPERM ; + goto out_up_write; } root_flags =btrfs_root_flags (&dest->root_item);btrfs_set_root_flags (&dest->root_item, root_flags |BTRFS_ROOT_SUBVOL_DEAD );spin_unlock (&dest->root_item_lock); -down_write (&fs_info->subvol_sem); - ret =may_destroy_subvol (dest);if (ret) - goto out_up_write; + goto out_undead;btrfs_init_block_rsv (&block_rsv,BTRFS_BLOCK_RSV_TEMP );/*
@@ -4488,7 +4490,7 @@ int btrfs_delete_subvolume(struct btrfs_*/ ret =btrfs_subvolume_reserve_metadata (root, &block_rsv,5 , true);if (ret) - goto out_up_write; + goto out_undead; trans =btrfs_start_transaction (root,0 );if (IS_ERR (trans)) {
@@ -4554,15 +4556,17 @@ out_end_trans: inode->i_flags |=S_DEAD ; out_release:btrfs_subvolume_release_metadata (root, &block_rsv); -out_up_write: -up_write (&fs_info->subvol_sem); +out_undead:if (ret) {spin_lock (&dest->root_item_lock); root_flags =btrfs_root_flags (&dest->root_item);btrfs_set_root_flags (&dest->root_item, root_flags & ~BTRFS_ROOT_SUBVOL_DEAD );spin_unlock (&dest->root_item_lock); - }else { + } +out_up_write: +up_write (&fs_info->subvol_sem); +if (!ret) {d_invalidate (dentry);btrfs_prune_dentries (dest);ASSERT (dest->send_in_progress ==0 );
Greg Kroah-Hartman
maintainerPATCH 224/346 btrfs: ref-verify: free ref cache before clearing mount opt
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fedor Pchelkin <[email protected]>
commit f03e274a8b29d1d1c1bbd7f764766cb5ca537ab7 upstream.
As clearing REF_VERIFY mount option indicates there were some errors in a ref-verify process, a ref cache is not relevant anymore and should be freed.
btrfs_free_ref_cache() requires REF_VERIFY option being set so call it just before clearing the mount option.
Found by Linux Verification Center (linuxtesting.org) with Syzkaller.
--- fs/btrfs/ref-verify.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
fs/btrfs/ref-verify.c +4 -2
@@ -889,8 +889,10 @@ int btrfs_ref_tree_mod(struct btrfs_fs_i out_unlock:spin_unlock (&fs_info->ref_verify_lock); out: -if (ret) +if (ret) { +btrfs_free_ref_cache (fs_info);btrfs_clear_opt (fs_info->mount_opt,REF_VERIFY ); + }return ret; }
@@ -1021,8 +1023,8 @@ int btrfs_build_ref_tree(struct btrfs_fs } }if (ret) { -btrfs_clear_opt (fs_info->mount_opt,REF_VERIFY );btrfs_free_ref_cache (fs_info); +btrfs_clear_opt (fs_info->mount_opt,REF_VERIFY ); }btrfs_free_path (path);return ret;
Greg Kroah-Hartman
maintainerPATCH 225/346 btrfs: tree-checker: fix inline ref size in error messages
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chung-Chiang Cheng <[email protected]>
commit f398e70dd69e6ceea71463a5380e6118f219197e upstream.
The error message should accurately reflect the size rather than the type.
--- fs/btrfs/tree-checker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/btrfs/tree-checker.c +1 -1
@@ -1436,7 +1436,7 @@ static int check_extent_item(struct exteif (unlikely (ptr +btrfs_extent_inline_ref_size (inline_type) > end)) {extent_err (leaf, slot,"inline ref item overflows extent item, ptr %lu iref size %u end %lu" , - ptr, inline_type, end); + ptr,btrfs_extent_inline_ref_size (inline_type), end);return -EUCLEAN ; }
Greg Kroah-Hartman
maintainerPATCH 226/346 btrfs: dont warn if discard range is not aligned to sector
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Sterba <[email protected]>
commit a208b3f132b48e1f94f620024e66fea635925877 upstream.
There's a warning in btrfs_issue_discard() when the range is not aligned to 512 bytes, originally added in 4d89d377bbb0 ("btrfs:btrfs_issue_discard ensure offset/length are aligned to sector boundaries"). We can't do sub-sector writes anyway so the adjustment is the only thing that we can do and the warning is unnecessary.
--- fs/btrfs/extent-tree.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/btrfs/extent-tree.c +2 -1
@@ -1260,7 +1260,8 @@ static int btrfs_issue_discard(struct blu64 bytes_left, end;u64 aligned_start =ALIGN (start,1 <<SECTOR_SHIFT ); -if (WARN_ON (start != aligned_start)) { +/* Adjust the range to be aligned to 512B sectors if necessary. */ +if (start != aligned_start) { len -= aligned_start - start; len =round_down (len,1 <<SECTOR_SHIFT ); start = aligned_start;
Greg Kroah-Hartman
maintainerPATCH 227/346 btrfs: defrag: reject unknown flags of btrfs_ioctl_defrag_range_args
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo <[email protected]>
commit 173431b274a9a54fc10b273b46e67f46bcf62d2e upstream.
Add extra sanity check for btrfs_ioctl_defrag_range_args::flags.
This is not really to enhance fuzzing tests, but as a preparation for future expansion on btrfs_ioctl_defrag_range_args.
In the future we're going to add new members, allowing more fine tuning for btrfs defrag. Without the -ENONOTSUPP error, there would be no way to detect if the kernel supports those new defrag features.
--- fs/btrfs/ioctl.c | 4 ++++ include/uapi/linux/btrfs.h | 3 +++ 2 files changed, 7 insertions(+)
fs/btrfs/ioctl.c +4 -0
@@ -2608,6 +2608,10 @@ static int btrfs_ioctl_defrag(struct fil ret = -EFAULT ; goto out; } +if (range.flags & ~BTRFS_DEFRAG_RANGE_FLAGS_SUPP ) { + ret = -EOPNOTSUPP ; + goto out; + }/* compression requires us to start the IO */ if ((range.flags &BTRFS_DEFRAG_RANGE_COMPRESS )) { range.flags |=BTRFS_DEFRAG_RANGE_START_IO ;
include/uapi/linux/btrfs.h +3 -0
@@ -614,6 +614,9 @@ struct btrfs_ioctl_clone_range_args {*/ #define BTRFS_DEFRAG_RANGE_COMPRESS 1#define BTRFS_DEFRAG_RANGE_START_IO 2 +#define BTRFS_DEFRAG_RANGE_FLAGS_SUPP (BTRFS_DEFRAG_RANGE_COMPRESS | \ + BTRFS_DEFRAG_RANGE_START_IO) +struct btrfs_ioctl_defrag_range_args {/* start of the defrag operation */ __u64 start;
Greg Kroah-Hartman
maintainerPATCH 228/346 btrfs: dont abort filesystem when attempting to snapshot deleted subvolume
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Omar Sandoval <[email protected]>
commit 7081929ab2572920e94d70be3d332e5c9f97095a upstream.
If the source file descriptor to the snapshot ioctl refers to a deleted subvolume, we get the following abort:
BTRFS: Transaction aborted (error -2)
WARNING: CPU: 0 PID: 833 at fs/btrfs/transaction.c:1875 create_pending_snapshot+0x1040/0x1190 [btrfs] Modules linked in: pata_acpi btrfs ata_piix libata scsi_mod virtio_net blake2b_generic xor net_failover virtio_rng failover scsi_common rng_core raid6_pq libcrc32c CPU: 0 PID: 833 Comm: t_snapshot_dele Not tainted 6.7.0-rc6 #2 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-1.fc39 04/01/2014 RIP: 0010:create_pending_snapshot+0x1040/0x1190 [btrfs] RSP: 0018:ffffa09c01337af8 EFLAGS: 00010282 RAX: 0000000000000000 RBX: ffff9982053e7c78 RCX: 0000000000000027 RDX: ffff99827dc20848 RSI: 0000000000000001 RDI: ffff99827dc20840 RBP: ffffa09c01337c00 R08: 0000000000000000 R09: ffffa09c01337998 R10: 0000000000000003 R11: ffffffffb96da248 R12: fffffffffffffffe R13: ffff99820535bb28 R14: ffff99820b7bd000 R15: ffff99820381ea80 FS: 00007fe20aadabc0(0000) GS:ffff99827dc00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000559a120b502f CR3: 00000000055b6000 CR4: 00000000000006f0 Call Trace: <TASK> ? create_pending_snapshot+0x1040/0x1190 [btrfs] ? __warn+0x81/0x130 ? create_pending_snapshot+0x1040/0x1190 [btrfs] ? report_bug+0x171/0x1a0 ? handle_bug+0x3a/0x70 ? exc_invalid_op+0x17/0x70 ? asm_exc_invalid_op+0x1a/0x20 ? create_pending_snapshot+0x1040/0x1190 [btrfs] ? create_pending_snapshot+0x1040/0x1190 [btrfs] create_pending_snapshots+0x92/0xc0 [btrfs] btrfs_commit_transaction+0x66b/0xf40 [btrfs] btrfs_mksubvol+0x301/0x4d0 [btrfs] btrfs_mksnapshot+0x80/0xb0 [btrfs] __btrfs_ioctl_snap_create+0x1c2/0x1d0 [btrfs] btrfs_ioctl_snap_create_v2+0xc4/0x150 [btrfs] btrfs_ioctl+0x8a6/0x2650 [btrfs] ? kmem_cache_free+0x22/0x340 ? do_sys_openat2+0x97/0xe0 __x64_sys_ioctl+0x97/0xd0 do_syscall_64+0x46/0xf0 entry_SYSCALL_64_after_hwframe+0x6e/0x76 RIP: 0033:0x7fe20abe83af RSP: 002b:00007ffe6eff1360 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 0000000000000004 RCX: 00007fe20abe83af RDX: 00007ffe6eff23c0 RSI: 0000000050009417 RDI: 0000000000000003 RBP: 0000000000000003 R08: 0000000000000000 R09: 00007fe20ad16cd0 R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 R13: 00007ffe6eff13c0 R14: 00007fe20ad45000 R15: 0000559a120b6d58 </TASK> ---[ end trace 0000000000000000 ]--- BTRFS: error (device vdc: state A) in create_pending_snapshot:1875: errno=-2 No such entry BTRFS info (device vdc: state EA): forced readonly BTRFS warning (device vdc: state EA): Skipping commit of aborted transaction. BTRFS: error (device vdc: state EA) in cleanup_transaction:2055: errno=-2 No such entry
This happens because create_pending_snapshot() initializes the new root item as a copy of the source root item. This includes the refs field, which is 0 for a deleted subvolume. The call to btrfs_insert_root() therefore inserts a root with refs == 0. btrfs_get_new_fs_root() then finds the root and returns -ENOENT if refs == 0, which causes create_pending_snapshot() to abort.
Fix it by checking the source root's refs before attempting the snapshot, but after locking subvol_sem to avoid racing with deletion.
--- fs/btrfs/ioctl.c | 3 +++ 1 file changed, 3 insertions(+)
fs/btrfs/ioctl.c +3 -0
@@ -790,6 +790,9 @@ static int create_snapshot(struct btrfs_return -EOPNOTSUPP ; } +if (btrfs_root_refs (&root->root_item) ==0 ) +return -ENOENT ; +if (!test_bit (BTRFS_ROOT_SHAREABLE , &root->state))return -EINVAL ;
Greg Kroah-Hartman
maintainerPATCH 229/346 rbd: dont move requests to the running list on errors
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ilya Dryomov <[email protected]>
commit ded080c86b3f99683774af0441a58fc2e3d60cae upstream.
The running list is supposed to contain requests that are pinning the exclusive lock, i.e. those that must be flushed before exclusive lock is released. When wake_lock_waiters() is called to handle an error, requests on the acquiring list are failed with that error and no flushing takes place. Briefly moving them to the running list is not only pointless but also harmful: if exclusive lock gets acquired before all of their state machines are scheduled and go through rbd_lock_del_request(), we trigger
rbd_assert(list_empty(&rbd_dev->running_list));
in rbd_try_acquire_lock().
--- drivers/block/rbd.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-)
drivers/block/rbd.c +14 -8
@@ -3452,14 +3452,15 @@ static bool rbd_lock_add_request(structstatic void rbd_lock_del_request (struct rbd_img_request *img_req) {struct rbd_device *rbd_dev = img_req->rbd_dev; -bool need_wakeup; +bool need_wakeup = false;lockdep_assert_held (&rbd_dev->lock_rwsem);spin_lock (&rbd_dev->lock_lists_lock); -rbd_assert (!list_empty (&img_req->lock_item)); -list_del_init (&img_req->lock_item); - need_wakeup = (rbd_dev->lock_state ==RBD_LOCK_STATE_RELEASING && -list_empty (&rbd_dev->running_list)); +if (!list_empty (&img_req->lock_item)) { +list_del_init (&img_req->lock_item); + need_wakeup = (rbd_dev->lock_state ==RBD_LOCK_STATE_RELEASING && +list_empty (&rbd_dev->running_list)); + }spin_unlock (&rbd_dev->lock_lists_lock);if (need_wakeup)complete (&rbd_dev->releasing_wait);
@@ -3842,14 +3843,19 @@ static void wake_lock_waiters(struct rbdreturn ; } -list_for_each_entry (img_req, &rbd_dev->acquiring_list, lock_item) { +while (!list_empty (&rbd_dev->acquiring_list)) { + img_req =list_first_entry (&rbd_dev->acquiring_list, + struct rbd_img_request, lock_item);mutex_lock (&img_req->state_mutex);rbd_assert (img_req->state ==RBD_IMG_EXCLUSIVE_LOCK ); +if (!result) +list_move_tail (&img_req->lock_item, + &rbd_dev->running_list); +else +list_del_init (&img_req->lock_item);rbd_img_schedule (img_req, result);mutex_unlock (&img_req->state_mutex); } - -list_splice_tail_init (&rbd_dev->acquiring_list, &rbd_dev->running_list); } static bool locker_equal(const struct ceph_locker *lhs,
Greg Kroah-Hartman
maintainerPATCH 230/346 exec: Fix error handling in begin_new_exec()
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bernd Edlinger <[email protected]>
commit 84c39ec57d409e803a9bb6e4e85daf1243e0e80b upstream.
If get_unused_fd_flags() fails, the error handling is incomplete because bprm->cred is already set to NULL, and therefore free_bprm will not unlock the cred_guard_mutex. Note there are two error conditions which end up here, one before and one after bprm->cred is cleared.
--- fs/exec.c | 3 +++ 1 file changed, 3 insertions(+)
fs/exec.c +3 -0
@@ -1408,6 +1408,9 @@ int begin_new_exec(struct linux_binprm * out_unlock:up_write (&me->signal->exec_update_lock); +if (!bprm->cred) +mutex_unlock (&me->signal->cred_guard_mutex); + out:return retval; }
Greg Kroah-Hartman
maintainerPATCH 231/346 wifi: iwlwifi: fix a memory corruption
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Emmanuel Grumbach <[email protected]>
commit cf4a0d840ecc72fcf16198d5e9c505ab7d5a5e4d upstream.
iwl_fw_ini_trigger_tlv::data is a pointer to a __le32, which means that if we copy to iwl_fw_ini_trigger_tlv::data + offset while offset is in bytes, we'll write past the buffer.
--- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +2 -2
@@ -1,6 +1,6 @@// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* -* Copyright (C) 2018-2023 Intel Corporation +* Copyright (C) 2018-2024 Intel Corporation */ #include <linux/firmware.h> #include "iwl-drv.h"
@@ -1096,7 +1096,7 @@ static int iwl_dbg_tlv_override_trig_nod node_trig = (void *)node_tlv->data; } -memcpy (node_trig->data + offset, trig->data, trig_data_len); +memcpy ((u8 *)node_trig->data + offset, trig->data, trig_data_len); node_tlv->length =cpu_to_le32 (size);if (policy &IWL_FW_INI_APPLY_POLICY_OVERRIDE_CFG ) {
Greg Kroah-Hartman
maintainerPATCH 232/346 nfsd: fix RELEASE_LOCKOWNER
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: NeilBrown <[email protected]>
commit edcf9725150e42beeca42d085149f4c88fa97afd upstream.
The test on so_count in nfsd4_release_lockowner() is nonsense and harmful. Revert to using check_for_locks(), changing that to not sleep.
First: harmful.
As is documented in the kdoc comment for nfsd4_release_lockowner(), the test on so_count can transiently return a false positive resulting in a return of NFS4ERR_LOCKS_HELD when in fact no locks are held. This is clearly a protocol violation and with the Linux NFS client it can cause incorrect behaviour.
If RELEASE_LOCKOWNER is sent while some other thread is still processing a LOCK request which failed because, at the time that request was received, the given owner held a conflicting lock, then the nfsd thread processing that LOCK request can hold a reference (conflock) to the lock owner that causes nfsd4_release_lockowner() to return an incorrect error.
The Linux NFS client ignores that NFS4ERR_LOCKS_HELD error because it never sends NFS4_RELEASE_LOCKOWNER without first releasing any locks, so it knows that the error is impossible. It assumes the lock owner was in fact released so it feels free to use the same lock owner identifier in some later locking request.
When it does reuse a lock owner identifier for which a previous RELEASE failed, it will naturally use a lock_seqid of zero. However the server, which didn't release the lock owner, will expect a larger lock_seqid and so will respond with NFS4ERR_BAD_SEQID.
So clearly it is harmful to allow a false positive, which testing so_count allows.
The test is nonsense because ... well... it doesn't mean anything.
so_count is the sum of three different counts.
1/ the set of states listed on so_stateids
2/ the set of active vfs locks owned by any of those states 3/ various transient counts such as for conflicting locks.
When it is tested against '2' it is clear that one of these is the transient reference obtained by find_lockowner_str_locked(). It is not clear what the other one is expected to be.
In practice, the count is often 2 because there is precisely one state on so_stateids. If there were more, this would fail.
In my testing I see two circumstances when RELEASE_LOCKOWNER is called. In one case, CLOSE is called before RELEASE_LOCKOWNER. That results in all the lock states being removed, and so the lockowner being discarded (it is removed when there are no more references which usually happens when the lock state is discarded). When nfsd4_release_lockowner() finds that the lock owner doesn't exist, it returns success.
The other case shows an so_count of '2' and precisely one state listed in so_stateid. It appears that the Linux client uses a separate lock owner for each file resulting in one lock state per lock owner, so this test on '2' is safe. For another client it might not be safe.
So this patch changes check_for_locks() to use the (newish) find_any_file_locked() so that it doesn't take a reference on the nfs4_file and so never calls nfsd_file_put(), and so never sleeps. With this check is it safe to restore the use of check_for_locks() rather than testing so_count against the mysterious '2'.
--- fs/nfsd/nfs4state.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-)
fs/nfsd/nfs4state.c +15 -11
@@ -7911,14 +7911,16 @@ check_for_locks(struct nfs4_file *fp, st {struct file_lock *fl;int status = false; -struct nfsd_file *nf =find_any_file (fp); +struct nfsd_file *nf;struct inode *inode;struct file_lock_context *flctx; +spin_lock (&fp->fi_lock); + nf =find_any_file_locked (fp);if (!nf) {/* Any valid lock stateid should have some sort of access */ WARN_ON_ONCE (1 ); -return status; + goto out; } inode =file_inode (nf->nf_file);
@@ -7934,7 +7936,8 @@ check_for_locks(struct nfs4_file *fp, st }spin_unlock (&flctx->flc_lock); } -nfsd_file_put (nf); +out: +spin_unlock (&fp->fi_lock);return status; }
@@ -7944,10 +7947,8 @@ check_for_locks(struct nfs4_file *fp, st* @cstate: NFSv4 COMPOUND state * @u: RELEASE_LOCKOWNER arguments * -* The lockowner's so_count is bumped when a lock record is added -* or when copying a conflicting lock. The latter case is brief, -* but can lead to fleeting false positives when looking for -* locks-in-use. +* Check if theree are any locks still held and if not - free the lockowner +* and any lock state that is owned. * * Return values: * %nfs_ok: lockowner released or not found
@@ -7983,10 +7984,13 @@ nfsd4_release_lockowner(struct svc_rqstspin_unlock (&clp->cl_lock);return nfs_ok; } -if (atomic_read (&lo->lo_owner.so_count) !=2 ) { -spin_unlock (&clp->cl_lock); -nfs4_put_stateowner (&lo->lo_owner); -return nfserr_locks_held; + +list_for_each_entry (stp, &lo->lo_owner.so_stateids, st_perstateowner) { +if (check_for_locks (stp->st_stid.sc_file, lo)) { +spin_unlock (&clp->cl_lock); +nfs4_put_stateowner (&lo->lo_owner); +return nfserr_locks_held; + } }unhash_lockowner_locked (lo);while (!list_empty (&lo->lo_owner.so_stateids)) {
Greg Kroah-Hartman
maintainerPATCH 233/346 ovl: mark xwhiteouts directory with overlay.opaque=x
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <[email protected]>
commit 420332b94119cdc7db4477cc88484691cb92ae71 upstream.
An opaque directory cannot have xwhiteouts, so instead of marking an xwhiteouts directory with a new xattr, overload overlay.opaque xattr for marking both opaque dir ('y') and xwhiteouts dir ('x').
This is more efficient as the overlay.opaque xattr is checked during lookup of directory anyway.
This also prevents unnecessary checking the xattr when reading a directory without xwhiteouts, i.e. most of the time.
Note that the xwhiteouts marker is not checked on the upper layer and on the last layer in lowerstack, where xwhiteouts are not expected.
--- Documentation/filesystems/overlayfs.rst | 16 +++++++-- fs/overlayfs/namei.c | 43 ++++++++++++++++--------- fs/overlayfs/overlayfs.h | 23 ++++++++++--- fs/overlayfs/ovl_entry.h | 4 +- fs/overlayfs/readdir.c | 7 ++-- fs/overlayfs/super.c | 15 +++++++++ fs/overlayfs/util.c | 53 ++++++++++++++++++-------------- 7 files changed, 110 insertions(+), 51 deletions(-)
Documentation/filesystems/overlayfs.rst +13 -3
@@ -145,7 +145,9 @@ filesystem, an overlay filesystem needs that files have been removed. This is done using whiteouts and opaque directories (non-directories are always opaque). -A whiteout is created as a character device with 0/0 device number. +A whiteout is created as a character device with 0/0 device number or +as a zero-size regular file with the xattr "trusted.overlay.whiteout". + When a whiteout is found in the upper level of a merged directory, any matching name in the lower level is ignored, and the whiteout itself is also hidden.
@@ -154,6 +156,13 @@ A directory is made opaque by setting th to "y". Where the upper filesystem contains an opaque directory, any directory in the lower filesystem with the same name is ignored. +An opaque directory should not conntain any whiteouts, because they do not +serve any purpose. A merge directory containing regular files with the xattr +"trusted.overlay.whiteout", should be additionally marked by setting the xattr +"trusted.overlay.opaque" to "x" on the merge directory itself. +This is needed to avoid the overhead of checking the "trusted.overlay.whiteout" +on all entries during readdir in the common case. + readdir -------
@@ -534,8 +543,9 @@ A lower dir with a regular whiteout will mount, so to support storing an effective whiteout file in an overlayfs mount an alternative form of whiteout is supported. This form is a regular, zero-size file with the "overlay.whiteout" xattr set, inside a directory with the -"overlay.whiteouts" xattr set. Such whiteouts are never created by overlayfs, -but can be used by userspace tools (like containers) that generate lower layers. +"overlay.opaque" xattr set to "x" (see `whiteouts and opaque directories`_). +These alternative whiteouts are never created by overlayfs, but can be used by +userspace tools (like containers) that generate lower layers. These alternative whiteouts can be escaped using the standard xattr escape mechanism in order to properly nest to any depth.
fs/overlayfs/namei.c +27 -16
126 lines not on this page · raw message
fs/overlayfs/overlayfs.h +17 -6
@@ -50,7 +50,6 @@ enum ovl_xattr {OVL_XATTR_METACOPY ,OVL_XATTR_PROTATTR , OVL_XATTR_XWHITEOUT, - OVL_XATTR_XWHITEOUTS, }; enum ovl_inode_flag {
@@ -70,6 +69,8 @@ enum ovl_entry_flag {OVL_E_UPPER_ALIAS ,OVL_E_OPAQUE ,OVL_E_CONNECTED , +/* Lower stack may contain xwhiteout entries */ + OVL_E_XWHITEOUTS, }; enum {
@@ -471,6 +472,10 @@ bool ovl_dentry_test_flag(unsigned longbool ovl_dentry_is_opaque (struct dentry *dentry);bool ovl_dentry_is_whiteout (struct dentry *dentry);void ovl_dentry_set_opaque (struct dentry *dentry); +bool ovl_dentry_has_xwhiteouts (struct dentry *dentry); +void ovl_dentry_set_xwhiteouts (struct dentry *dentry); +void ovl_layer_set_xwhiteouts (struct ovl_fs *ofs, +const struct ovl_layer *layer);bool ovl_dentry_has_upper_alias (struct dentry *dentry);void ovl_dentry_set_upper_alias (struct dentry *dentry);bool ovl_dentry_needs_data_copy_up (struct dentry *dentry,int flags);
@@ -488,11 +493,10 @@ struct file *ovl_path_open(const structint ovl_copy_up_start (struct dentry *dentry,int flags);void ovl_copy_up_end (struct dentry *dentry);bool ovl_already_copied_up (struct dentry *dentry,int flags); -bool ovl_path_check_dir_xattr (struct ovl_fs *ofs,const struct path *path, -enum ovl_xattr ox); +char ovl_get_dir_xattr_val (struct ovl_fs *ofs,const struct path *path, +enum ovl_xattr ox);bool ovl_path_check_origin_xattr (struct ovl_fs *ofs,const struct path *path);bool ovl_path_check_xwhiteout_xattr (struct ovl_fs *ofs,const struct path *path); -bool ovl_path_check_xwhiteouts_xattr (struct ovl_fs *ofs,const struct path *path);bool ovl_init_uuid_xattr (struct super_block *sb,struct ovl_fs *ofs,const struct path *upperpath);
@@ -567,7 +571,13 @@ static inline bool ovl_is_impuredir(stru .mnt = ovl_upper_mnt(ofs), }; -return ovl_path_check_dir_xattr (ofs, &upperpath,OVL_XATTR_IMPURE ); +return ovl_get_dir_xattr_val (ofs, &upperpath,OVL_XATTR_IMPURE ) =='y' ; +} + +static inline char ovl_get_opaquedir_val (struct ovl_fs *ofs, +const struct path *path) +{ +return ovl_get_dir_xattr_val (ofs, path,OVL_XATTR_OPAQUE ); }static inline bool ovl_redirect_follow (struct ovl_fs *ofs)
@@ -674,7 +684,8 @@ int ovl_get_index_name(struct ovl_fs *ofstruct dentry *ovl_get_index_fh (struct ovl_fs *ofs,struct ovl_fh *fh);struct dentry *ovl_lookup_index (struct ovl_fs *ofs,struct dentry *upper,struct dentry *origin,bool verify); -int ovl_path_next (int idx,struct dentry *dentry,struct path *path); +int ovl_path_next (int idx,struct dentry *dentry,struct path *path, +const struct ovl_layer **layer);int ovl_verify_lowerdata (struct dentry *dentry);struct dentry *ovl_lookup (struct inode *dir,struct dentry *dentry,unsigned int flags);
fs/overlayfs/ovl_entry.h +3 -1
@@ -40,6 +40,8 @@ struct ovl_layer {int idx;/* One fsid per unique underlying sb (upper fsid == 0) */ int fsid; +/* xwhiteouts were found on this layer */ +bool has_xwhiteouts; };struct ovl_path {
@@ -59,7 +61,7 @@ struct ovl_fs {unsigned int numfs;/* Number of data-only lower layers */ unsigned int numdatalayer; -const struct ovl_layer *layers; +struct ovl_layer *layers;struct ovl_sb *fs;/* workbasedir is the path at workdir= mount option */ struct dentry *workbasedir;
fs/overlayfs/readdir.c +4 -3
@@ -305,8 +305,6 @@ static inline int ovl_dir_read(const strif (IS_ERR (realfile))return PTR_ERR (realfile); - rdd->in_xwhiteouts_dir = rdd->dentry && -ovl_path_check_xwhiteouts_xattr (OVL_FS (rdd->dentry->d_sb), realpath); rdd->first_maybe_whiteout =NULL ; rdd->ctx.pos =0 ; do {
@@ -359,10 +357,13 @@ static int ovl_dir_read_merged(struct de .is_lowest = false, };int idx, next; +const struct ovl_layer *layer;for (idx =0 ; idx !=-1 ; idx = next) { - next =ovl_path_next (idx, dentry, &realpath); + next =ovl_path_next (idx, dentry, &realpath, &layer); rdd.is_upper =ovl_dentry_upper (dentry) == realpath.dentry; + rdd.in_xwhiteouts_dir = layer->has_xwhiteouts && +ovl_dentry_has_xwhiteouts (dentry);if (next !=-1 ) { err =ovl_dir_read (&realpath, &rdd);
fs/overlayfs/super.c +15 -0
@@ -1250,6 +1250,7 @@ static struct dentry *ovl_get_root(struc struct ovl_entry *oe) {struct dentry *root; +struct ovl_fs *ofs =OVL_FS (sb);struct ovl_path *lowerpath =ovl_lowerstack (oe);unsigned long ino =d_inode (lowerpath->dentry)->i_ino;int fsid = lowerpath->layer->fsid;
@@ -1271,6 +1272,20 @@ static struct dentry *ovl_get_root(strucovl_set_flag (OVL_IMPURE ,d_inode (root)); } +/* Look for xwhiteouts marker except in the lowermost layer */ +for (int i =0 ; i <ovl_numlower (oe) -1 ; i++, lowerpath++) { +struct path path = { + .mnt = lowerpath->layer->mnt, + .dentry = lowerpath->dentry, + }; + +/* overlay.opaque=x means xwhiteouts directory */ +if (ovl_get_opaquedir_val (ofs, &path) =='x' ) { +ovl_layer_set_xwhiteouts (ofs, lowerpath->layer); +ovl_dentry_set_xwhiteouts (root); + } + } +/* Root is always merge -> can have whiteouts */ ovl_set_flag (OVL_WHITEOUTS ,d_inode (root));ovl_dentry_set_flag (OVL_E_CONNECTED , root);
fs/overlayfs/util.c +31 -22
90 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 234/346 hv_netvsc: Calculate correct ring size when PAGE_SIZE is not 4 Kbytes
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Kelley <[email protected]>
commit 6941f67ad37d5465b75b9ffc498fcf6897a3c00e upstream.
Current code in netvsc_drv_init() incorrectly assumes that PAGE_SIZE is 4 Kbytes, which is wrong on ARM64 with 16K or 64K page size. As a result, the default VMBus ring buffer size on ARM64 with 64K page size is 8 Mbytes instead of the expected 512 Kbytes. While this doesn't break anything, a typical VM with 8 vCPUs and 8 netvsc channels wastes 120 Mbytes (8 channels * 2 ring buffers/channel * 7.5 Mbytes/ring buffer).
Unfortunately, the module parameter specifying the ring buffer size is in units of 4 Kbyte pages. Ideally, it should be in units that are independent of PAGE_SIZE, but backwards compatibility prevents changing that now.
Fix this by having netvsc_drv_init() hardcode 4096 instead of using PAGE_SIZE when calculating the ring buffer size in bytes. Also use the VMBUS_RING_SIZE macro to ensure proper alignment when running with page size larger than 4K.
--- drivers/net/hyperv/netvsc_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/hyperv/netvsc_drv.c +2 -2
@@ -44,7 +44,7 @@static unsigned int ring_size__ro_after_init =128 ;module_param (ring_size, uint,0444 ); -MODULE_PARM_DESC (ring_size,"Ring buffer size (# of pages)" ); +MODULE_PARM_DESC (ring_size,"Ring buffer size (# of 4K pages)" );unsigned int netvsc_ring_bytes__ro_after_init ; static const u32 default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE |
@@ -2805,7 +2805,7 @@ static int __init netvsc_drv_init(void)pr_info ("Increased ring_size to %u (min allowed)\n" , ring_size); } - netvsc_ring_bytes = ring_size *PAGE_SIZE ; + netvsc_ring_bytes =VMBUS_RING_SIZE (ring_size *4096 );register_netdevice_notifier (&netvsc_netdev_notifier);
Greg Kroah-Hartman
maintainerPATCH 235/346 netfilter: nft_chain_filter: handle NETDEV_UNREGISTER for inet/ingress basechain
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso <[email protected]>
commit 01acb2e8666a6529697141a6017edbf206921913 upstream.
Remove netdevice from inet/ingress basechain in case NETDEV_UNREGISTER event is reported, otherwise a stale reference to netdevice remains in the hook list.
--- net/netfilter/nft_chain_filter.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
net/netfilter/nft_chain_filter.c +9 -2
@@ -357,9 +357,10 @@ static int nf_tables_netdev_event(struct unsigned long event, void *ptr) { struct net_device *dev = netdev_notifier_info_to_dev(ptr); +struct nft_base_chain *basechain;struct nftables_pernet *nft_net; -struct nft_table *table;struct nft_chain *chain, *nr; +struct nft_table *table;struct nft_ctx ctx = { .net =dev_net (dev), };
@@ -371,7 +372,8 @@ static int nf_tables_netdev_event(struct nft_net =nft_pernet (ctx.net);mutex_lock (&nft_net->commit_mutex);list_for_each_entry (table, &nft_net->tables, list) { -if (table->family !=NFPROTO_NETDEV ) +if (table->family !=NFPROTO_NETDEV && + table->family !=NFPROTO_INET )continue ; ctx.family = table->family;
@@ -380,6 +382,11 @@ static int nf_tables_netdev_event(structif (!nft_is_base_chain (chain))continue ; + basechain =nft_base_chain (chain); +if (table->family ==NFPROTO_INET && + basechain->ops.hooknum !=NF_INET_INGRESS ) +continue ; + ctx.chain = chain;nft_netdev_event (event, dev, &ctx); }
Greg Kroah-Hartman
maintainerPATCH 236/346 netfilter: nf_tables: reject QUEUE/DROP verdict parameters
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
commit f342de4e2f33e0e39165d8639387aa6c19dff660 upstream.
This reverts commit e0abdadcc6e1.
core.c:nf_hook_slow assumes that the upper 16 bits of NF_DROP verdicts contain a valid errno, i.e. -EPERM, -EHOSTUNREACH or similar, or 0.
Due to the reverted commit, its possible to provide a positive value, e.g. NF_ACCEPT (1), which results in use-after-free.
Its not clear to me why this commit was made.
NF_QUEUE is not used by nftables; "queue" rules in nftables will result in use of "nft_queue" expression.
If we later need to allow specifiying errno values from userspace (do not know why), this has to call NF_DROP_GETERR and check that "err <= 0" holds true.
--- net/netfilter/nf_tables_api.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-)
net/netfilter/nf_tables_api.c +6 -10
@@ -10909,16 +10909,10 @@ static int nft_verdict_init(const struct data->verdict.code =ntohl (nla_get_be32 (tb[NFTA_VERDICT_CODE ]));switch (data->verdict.code) { -default : -switch (data->verdict.code &NF_VERDICT_MASK ) { -case NF_ACCEPT : -case NF_DROP : -case NF_QUEUE : -break ; -default : -return -EINVAL ; - } - fallthrough; +case NF_ACCEPT : +case NF_DROP : +case NF_QUEUE : +break ;case NFT_CONTINUE :case NFT_BREAK :case NFT_RETURN :
@@ -10953,6 +10947,8 @@ static int nft_verdict_init(const struct data->verdict.chain = chain;break ; +default : +return -EINVAL ; } desc->len =sizeof (data->verdict);
Greg Kroah-Hartman
maintainerPATCH 237/346 platform/x86: intel-uncore-freq: Fix types in sysfs callbacks
In reply to Greg Kroah-Hartman6.7-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nathan Chancellor <[email protected]>
commit 416de0246f35f43d871a57939671fe814f4455ee upstream.
When booting a kernel with CONFIG_CFI_CLANG, there is a CFI failure when accessing any of the values under /sys/devices/system/cpu/intel_uncore_frequency/package_00_die_00:
$ cat /sys/devices/system/cpu/intel_uncore_frequency/package_00_die_00/max_freq_khz fish: Job 1, 'cat /sys/devices/system/cpu/int…' terminated by signal SIGSEGV (Address boundary error)
$ sudo dmesg &| grep 'CFI failure' [ 170.953925] CFI failure at kobj_attr_show+0x19/0x30 (target: show_max_freq_khz+0x0/0xc0 [intel_uncore_frequency_common]; expected type: 0xd34078c5
The sysfs callback functions such as show_domain_id() are written as if they are going to be called by dev_attr_show() but as the above message shows, they are instead called by kobj_attr_show(). kCFI checks that the destination of an indirect jump has the exact same type as the prototype of the function pointer it is called through and fails when they do not.
These callbacks are called through kobj_attr_show() because uncore_root_kobj was initialized with kobject_create_and_add(), which means uncore_root_kobj has a ->sysfs_ops of kobj_sysfs_ops from kobject_create(), which uses kobj_attr_show() as its ->show() value.
The only reason there has not been a more noticeable problem until this point is that 'struct kobj_attribute' and 'struct device_attribute' have the same layout, so getting the callback from container_of() works the same with either value.
Change all the callbacks and their uses to be compatible with kobj_attr_show() and kobj_attr_store(), which resolves the kCFI failure and allows the sysfs files to work properly.
--- drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c | 82 +++++----- drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h | 32 +-- 2 files changed, 57 insertions(+), 57 deletions(-)
drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c +41 -41
@@ -23,23 +23,23 @@ static int (*uncore_read)(struct uncore_static int (*uncore_write)(struct uncore_data *data,unsigned int input,unsigned int min_max);static int (*uncore_read_freq)(struct uncore_data *data,unsigned int *freq); -static ssize_t show_domain_id (struct device *dev,struct device_attribute *attr,char *buf) +static ssize_t show_domain_id (struct kobject *kobj,struct kobj_attribute *attr,char *buf) { - struct uncore_data *data = container_of(attr, struct uncore_data, domain_id_dev_attr); + struct uncore_data *data = container_of(attr, struct uncore_data, domain_id_kobj_attr);return sprintf (buf,"%u\n" , data->domain_id); } -static ssize_t show_fabric_cluster_id (struct device *dev,struct device_attribute *attr,char *buf) +static ssize_t show_fabric_cluster_id (struct kobject *kobj,struct kobj_attribute *attr,char *buf) { - struct uncore_data *data = container_of(attr, struct uncore_data, fabric_cluster_id_dev_attr); + struct uncore_data *data = container_of(attr, struct uncore_data, fabric_cluster_id_kobj_attr);return sprintf (buf,"%u\n" , data->cluster_id); } -static ssize_t show_package_id (struct device *dev,struct device_attribute *attr,char *buf) +static ssize_t show_package_id (struct kobject *kobj,struct kobj_attribute *attr,char *buf) { - struct uncore_data *data = container_of(attr, struct uncore_data, package_id_dev_attr); + struct uncore_data *data = container_of(attr, struct uncore_data, package_id_kobj_attr);return sprintf (buf,"%u\n" , data->package_id); }
@@ -97,30 +97,30 @@ static ssize_t show_perf_status_freq_khz }#define store_uncore_min_max (name, min_max) \ - static ssize_t store_##name(struct device *dev, \ - struct device_attribute *attr, \ + static ssize_t store_##name(struct kobject *kobj, \ + struct kobj_attribute *attr, \ const char *buf, size_t count) \ { \ - struct uncore_data *data = container_of(attr, struct uncore_data, name##_dev_attr);\ + struct uncore_data *data = container_of(attr, struct uncore_data, name##_kobj_attr);\ \ return store_min_max_freq_khz(data, buf, count, \ min_max); \ }#define show_uncore_min_max (name, min_max) \ - static ssize_t show_##name(struct device *dev, \ - struct device_attribute *attr, char *buf)\ + static ssize_t show_##name(struct kobject *kobj, \ + struct kobj_attribute *attr, char *buf)\ { \ - struct uncore_data *data = container_of(attr, struct uncore_data, name##_dev_attr);\ + struct uncore_data *data = container_of(attr, struct uncore_data, name##_kobj_attr);\ \ return show_min_max_freq_khz(data, buf, min_max); \ }#define show_uncore_perf_status (name) \ - static ssize_t show_##name(struct device *dev, \ - struct device_attribute *attr, char *buf)\ + static ssize_t show_##name(struct kobject *kobj, \ + struct kobj_attribute *attr, char *buf)\ { \ - struct uncore_data *data = container_of(attr, struct uncore_data, name##_dev_attr);\ + struct uncore_data *data = container_of(attr, struct uncore_data, name##_kobj_attr);\ \ return show_perf_status_freq_khz(data, buf); \ }
@@ -134,11 +134,11 @@ show_uncore_min_max(max_freq_khz, 1);show_uncore_perf_status (current_freq_khz);#define show_uncore_data (member_name) \ - static ssize_t show_##member_name(struct device *dev, \ - struct device_attribute *attr, char *buf)\ + static ssize_t show_##member_name(struct kobject *kobj, \ + struct kobj_attribute *attr, char *buf)\ { \ struct uncore_data *data = container_of(attr, struct uncore_data,\ - member_name##_dev_attr);\ + member_name##_kobj_attr);\ \ return sysfs_emit(buf, "%u\n", \ data->member_name); \
@@ -149,29 +149,29 @@ show_uncore_data(initial_max_freq_khz);#define init_attribute_rw (_name) \ do { \ - sysfs_attr_init(&data->_name##_dev_attr.attr); \ - data->_name##_dev_attr.show = show_##_name; \ - data->_name##_dev_attr.store = store_##_name; \ - data->_name##_dev_attr.attr.name = #_name; \ - data->_name##_dev_attr.attr.mode = 0644; \ + sysfs_attr_init(&data->_name##_kobj_attr.attr); \ + data->_name##_kobj_attr.show = show_##_name; \ + data->_name##_kobj_attr.store = store_##_name; \ + data->_name##_kobj_attr.attr.name = #_name; \ + data->_name##_kobj_attr.attr.mode = 0644; \ } while (0)#define init_attribute_ro (_name) \ do { \ - sysfs_attr_init(&data->_name##_dev_attr.attr); \ - data->_name##_dev_attr.show = show_##_name; \ - data->_name##_dev_attr.store = NULL; \ - data->_name##_dev_attr.attr.name = #_name; \ - data->_name##_dev_attr.attr.mode = 0444; \ + sysfs_attr_init(&data->_name##_kobj_attr.attr); \ + data->_name##_kobj_attr.show = show_##_name; \ + data->_name##_kobj_attr.store = NULL; \ + data->_name##_kobj_attr.attr.name = #_name; \ + data->_name##_kobj_attr.attr.mode = 0444; \ } while (0)#define init_attribute_root_ro (_name) \ do { \ - sysfs_attr_init(&data->_name##_dev_attr.attr); \ - data->_name##_dev_attr.show = show_##_name; \ - data->_name##_dev_attr.store = NULL; \ - data->_name##_dev_attr.attr.name = #_name; \ - data->_name##_dev_attr.attr.mode = 0400; \ + sysfs_attr_init(&data->_name##_kobj_attr.attr); \ + data->_name##_kobj_attr.show = show_##_name; \ + data->_name##_kobj_attr.store = NULL; \ + data->_name##_kobj_attr.attr.name = #_name; \ + data->_name##_kobj_attr.attr.mode = 0400; \ } while (0)static int create_attr_group (struct uncore_data *data,char *name)
@@ -186,21 +186,21 @@ static int create_attr_group(struct uncoif (data->domain_id !=UNCORE_DOMAIN_ID_INVALID ) {init_attribute_root_ro (domain_id); - data->uncore_attrs[index++] = &data->domain_id_dev_attr.attr; + data->uncore_attrs[index++] = &data->domain_id_kobj_attr.attr;init_attribute_root_ro (fabric_cluster_id); - data->uncore_attrs[index++] = &data->fabric_cluster_id_dev_attr.attr; + data->uncore_attrs[index++] = &data->fabric_cluster_id_kobj_attr.attr;init_attribute_root_ro (package_id); - data->uncore_attrs[index++] = &data->package_id_dev_attr.attr; + data->uncore_attrs[index++] = &data->package_id_kobj_attr.attr; } - data->uncore_attrs[index++] = &data->max_freq_khz_dev_attr.attr; - data->uncore_attrs[index++] = &data->min_freq_khz_dev_attr.attr; - data->uncore_attrs[index++] = &data->initial_min_freq_khz_dev_attr.attr; - data->uncore_attrs[index++] = &data->initial_max_freq_khz_dev_attr.attr; + data->uncore_attrs[index++] = &data->max_freq_khz_kobj_attr.attr; + data->uncore_attrs[index++] = &data->min_freq_khz_kobj_attr.attr; + data->uncore_attrs[index++] = &data->initial_min_freq_khz_kobj_attr.attr; + data->uncore_attrs[index++] = &data->initial_max_freq_khz_kobj_attr.attr; ret =uncore_read_freq (data, &freq);if (!ret) - data->uncore_attrs[index++] = &data->current_freq_khz_dev_attr.attr; + data->uncore_attrs[index++] = &data->current_freq_khz_kobj_attr.attr; data->uncore_attrs[index] =NULL ;
drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h +16 -16
@@ -26,14 +26,14 @@* @instance_id: Unique instance id to append to directory name * @name: Sysfs entry name for this instance * @uncore_attr_group: Attribute group storage -* @max_freq_khz_dev_attr: Storage for device attribute max_freq_khz -* @mix_freq_khz_dev_attr: Storage for device attribute min_freq_khz -* @initial_max_freq_khz_dev_attr: Storage for device attribute initial_max_freq_khz -* @initial_min_freq_khz_dev_attr: Storage for device attribute initial_min_freq_khz -* @current_freq_khz_dev_attr: Storage for device attribute current_freq_khz -* @domain_id_dev_attr: Storage for device attribute domain_id -* @fabric_cluster_id_dev_attr: Storage for device attribute fabric_cluster_id -* @package_id_dev_attr: Storage for device attribute package_id +* @max_freq_khz_kobj_attr: Storage for kobject attribute max_freq_khz +* @mix_freq_khz_kobj_attr: Storage for kobject attribute min_freq_khz +* @initial_max_freq_khz_kobj_attr: Storage for kobject attribute initial_max_freq_khz +* @initial_min_freq_khz_kobj_attr: Storage for kobject attribute initial_min_freq_khz +* @current_freq_khz_kobj_attr: Storage for kobject attribute current_freq_khz +* @domain_id_kobj_attr: Storage for kobject attribute domain_id +* @fabric_cluster_id_kobj_attr: Storage for kobject attribute fabric_cluster_id +* @package_id_kobj_attr: Storage for kobject attribute package_id * @uncore_attrs: Attribute storage for group creation * * This structure is used to encapsulate all data related to uncore sysfs
@@ -53,14 +53,14 @@ struct uncore_data {char name[32 ];struct attribute_group uncore_attr_group; -struct device_attribute max_freq_khz_dev_attr; -struct device_attribute min_freq_khz_dev_attr; -struct device_attribute initial_max_freq_khz_dev_attr; -struct device_attribute initial_min_freq_khz_dev_attr; -struct device_attribute current_freq_khz_dev_attr; -struct device_attribute domain_id_dev_attr; -struct device_attribute fabric_cluster_id_dev_attr; -struct device_attribute package_id_dev_attr; +struct kobj_attribute max_freq_khz_kobj_attr; +struct kobj_attribute min_freq_khz_kobj_attr; +struct kobj_attribute initial_max_freq_khz_kobj_attr; +struct kobj_attribute initial_min_freq_khz_kobj_attr; +struct kobj_attribute current_freq_khz_kobj_attr; +struct kobj_attribute domain_id_kobj_attr; +struct kobj_attribute fabric_cluster_id_kobj_attr; +struct kobj_attribute package_id_kobj_attr;struct attribute *uncore_attrs[9 ]; };