6.12.110-rc1 review
Subsystems (7)
Greg Kroah-Hartman
maintainerPATCH 684/1376 selftests/bpf: Fix incorrect error checking for pthread_create
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Feng Yang <[email protected]>
[ Upstream commit b04b8d4e198aefc863e7b702ececb957845b0c25 ]
pthread_create returns 0 on success and a positive error code on failure; it never returns a negative value. The current conditional branch can never be taken. Failures during thread creation are silently ignored, which will lead to invalid memory access when waiting on threads or dereferencing thread handles later.
--- tools/testing/selftests/bpf/test_progs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/testing/selftests/bpf/test_progs.c +1 -1
@@ -1561,7 +1561,7 @@ static void server_main(void) data[i].worker_id = i; data[i].sock_fd = env.worker_socks[i]; rc =pthread_create (&dispatcher_threads[i],NULL , dispatch_thread, &data[i]); -if (rc <0 ) { +if (rc) {perror ("Failed to launch dispatcher thread" );exit (EXIT_ERR_SETUP_INFRA ); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 685/1376 selftests/bpf: Fix memory leak on subtest_states reallocation
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Feng Yang <[email protected]>
[ Upstream commit 06efb01c6530e9cfc247178cb96aa8adb3beaf61 ]
Fix memory leak in subtest_states reallocation,
and revert subtest_num if allocation fails.
--- tools/testing/selftests/bpf/test_progs.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
tools/testing/selftests/bpf/test_progs.c +5 -4
@@ -468,18 +468,19 @@ bool test__start_subtest(const char *subtest_name)struct test_state *state = env.test_state;struct subtest_state *subtest_state;size_t sub_state_size =sizeof (*subtest_state); +void *tmp;if (env.subtest_state)test__end_subtest (); state->subtest_num++; - state->subtest_states = -realloc (state->subtest_states, - state->subtest_num * sub_state_size); -if (!state->subtest_states) { + tmp =realloc (state->subtest_states, state->subtest_num * sub_state_size); +if (!tmp) { + state->subtest_num--;fprintf (stderr,"Not enough memory to allocate subtest result\n" );return false; } + state->subtest_states = tmp; subtest_state = &state->subtest_states[state->subtest_num -1 ];
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 686/1376 cxl/region: Fix use-after-free in find_pos_and_ways() error path
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alison Schofield <[email protected]>
[ Upstream commit 15da704b732332cc1e8f121f624e5e6c05124c5d ]
The error path releases its reference to a switch decoder before logging an error that includes the decoder name. If the released reference is the last one, the decoder can be freed before the error message accesses its name.
Drop the reference after the error is reported.
--- drivers/cxl/core/region.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
drivers/cxl/core/region.c +3 -4
@@ -1779,14 +1779,13 @@ static int find_pos_and_ways(struct cxl_port *port, struct range *range,break ; } } -put_device (dev); -if (rc)dev_err (port->uport_dev,"failed to find %s:%s in target list of %s\n" ,dev_name (&port->dev), -dev_name (port->parent_dport->dport_dev), -dev_name (&cxlsd->cxld.dev)); +dev_name (port->parent_dport->dport_dev),dev_name (dev)); + +put_device (dev);return rc; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 687/1376 pinctrl: mediatek: Add EINT support for multiple addresses
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hao Chang <[email protected]>
[ Upstream commit 3ef9f710efcb5cc1335b5b09c16c757f703d7e5f ]
For flexible routing, eint will be divided into 5 bases, and it will obtain the operation address through the pins array.
Stable-dep-of: 88292b7103d2 ("pinctrl: mediatek: free EINT resources on unbind")
--- drivers/pinctrl/mediatek/mtk-eint.c | 313 +++++++++++------- drivers/pinctrl/mediatek/mtk-eint.h | 23 +- .../pinctrl/mediatek/pinctrl-mtk-common-v2.c | 37 ++- .../pinctrl/mediatek/pinctrl-mtk-common-v2.h | 1 + drivers/pinctrl/mediatek/pinctrl-paris.h | 7 + 5 files changed, 254 insertions(+), 127 deletions(-)
drivers/pinctrl/mediatek/mtk-eint.c +197 -116
@@ -1,11 +1,13 @@// SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2014-2018 MediaTek Inc. +// Copyright (c) 2014-2025 MediaTek Inc. /* * Library for MediaTek External Interrupt Support * * Author: Maoguang Meng <[email protected]> * Sean Wang <[email protected]> +* Hao Chang <[email protected]> +* Qingliang Li <[email protected]> * */
@@ -20,6 +22,7 @@#include <linux/platform_device.h> #include "mtk-eint.h" +#include "pinctrl-mtk-common-v2.h" #define MTK_EINT_EDGE_SENSITIVE 0#define MTK_EINT_LEVEL_SENSITIVE 1
@@ -68,13 +71,11 @@ static void __iomem *mtk_eint_get_offset(struct mtk_eint *eint, unsigned int eint_num, unsigned int offset) { -unsigned int eint_base =0 ; +unsigned int idx = eint->pins[eint_num].index; +unsigned int inst = eint->pins[eint_num].instance;void __iomem *reg; -if (eint_num >= eint->hw->ap_num) - eint_base = eint->hw->ap_num; - - reg = eint->base + offset + ((eint_num - eint_base) /32 ) *4 ; + reg = eint->base[inst] + offset + (idx /32 *4 );return reg; }
@@ -83,7 +84,7 @@ static unsigned int mtk_eint_can_en_debounce(struct mtk_eint *eint, unsigned int eint_num) {unsigned int sens; -unsigned int bit =BIT (eint_num %32 ); +unsigned int bit =BIT (eint->pins[eint_num].index %32 );void __iomem *reg =mtk_eint_get_offset (eint, eint_num, eint->regs->sens);
@@ -92,7 +93,7 @@ static unsigned int mtk_eint_can_en_debounce(struct mtk_eint *eint,else sens =MTK_EINT_EDGE_SENSITIVE ; -if (eint_num < eint->hw->db_cnt && sens !=MTK_EINT_EDGE_SENSITIVE ) +if (eint->pins[eint_num].debounce && sens !=MTK_EINT_EDGE_SENSITIVE )return 1 ;else return 0 ;
@@ -102,9 +103,9 @@ static int mtk_eint_flip_edge(struct mtk_eint *eint, int hwirq) {int start_level, curr_level;unsigned int reg_offset; -u32 mask =BIT (hwirq &0x1f ); -u32 port = (hwirq >>5 ) & eint->hw->port_mask; -void __iomem *reg = eint->base + (port <<2 ); +unsigned int mask =BIT (eint->pins[hwirq].index &0x1f ); +unsigned int port = (eint->pins[hwirq].index >>5 ) & eint->hw->port_mask; +void __iomem *reg = eint->base[eint->pins[hwirq].instance] + (port <<2 ); curr_level = eint->gpio_xlate->get_gpio_state (eint->pctl, hwirq);
@@ -126,11 +127,13 @@ static int mtk_eint_flip_edge(struct mtk_eint *eint, int hwirq)static void mtk_eint_mask (struct irq_data *d) {struct mtk_eint *eint =irq_data_get_irq_chip_data (d); -u32 mask =BIT (d->hwirq &0x1f ); +unsigned int idx = eint->pins[d->hwirq].index; +unsigned int inst = eint->pins[d->hwirq].instance; +unsigned int mask =BIT (idx &0x1f );void __iomem *reg =mtk_eint_get_offset (eint, d->hwirq, eint->regs->mask_set); - eint->cur_mask[d->hwirq >>5 ] &= ~mask; + eint->cur_mask[inst][idx >>5 ] &= ~mask;writel (mask, reg); }
@@ -138,22 +141,24 @@ static void mtk_eint_mask(struct irq_data *d)static void mtk_eint_unmask (struct irq_data *d) {struct mtk_eint *eint =irq_data_get_irq_chip_data (d); -u32 mask =BIT (d->hwirq &0x1f ); +unsigned int idx = eint->pins[d->hwirq].index; +unsigned int inst = eint->pins[d->hwirq].instance; +unsigned int mask =BIT (idx &0x1f );void __iomem *reg =mtk_eint_get_offset (eint, d->hwirq, eint->regs->mask_clr); - eint->cur_mask[d->hwirq >>5 ] |= mask; + eint->cur_mask[inst][idx >>5 ] |= mask;writel (mask, reg); -if (eint->dual_edge[d->hwirq]) +if (eint->pins[d->hwirq].dual_edge)mtk_eint_flip_edge (eint, d->hwirq); }static unsigned int mtk_eint_get_mask (struct mtk_eint *eint,unsigned int eint_num) { -unsigned int bit =BIT (eint_num %32 ); +unsigned int bit =BIT (eint->pins[eint_num].index %32 );void __iomem *reg =mtk_eint_get_offset (eint, eint_num, eint->regs->mask);
@@ -163,7 +168,7 @@ static unsigned int mtk_eint_get_mask(struct mtk_eint *eint,static void mtk_eint_ack (struct irq_data *d) {struct mtk_eint *eint =irq_data_get_irq_chip_data (d); -u32 mask =BIT (d->hwirq &0x1f ); +unsigned int mask =BIT (eint->pins[d->hwirq].index &0x1f );void __iomem *reg =mtk_eint_get_offset (eint, d->hwirq, eint->regs->ack);
@@ -174,7 +179,7 @@ static int mtk_eint_set_type(struct irq_data *d, unsigned int type) {struct mtk_eint *eint =irq_data_get_irq_chip_data (d);bool masked; -u32 mask =BIT (d->hwirq &0x1f ); +unsigned int mask =BIT (eint->pins[d->hwirq].index &0x1f );void __iomem *reg; if (((type & IRQ_TYPE_EDGE_BOTH) && (type & IRQ_TYPE_LEVEL_MASK)) ||
@@ -186,9 +191,9 @@ static int mtk_eint_set_type(struct irq_data *d, unsigned int type) }if ((type &IRQ_TYPE_EDGE_BOTH ) ==IRQ_TYPE_EDGE_BOTH ) - eint->dual_edge[d->hwirq] =1 ; + eint->pins[d->hwirq].dual_edge =1 ;else - eint->dual_edge[d->hwirq] =0 ; + eint->pins[d->hwirq].dual_edge =0 ;if (!mtk_eint_get_mask (eint, d->hwirq)) {mtk_eint_mask (d);
@@ -223,27 +228,32 @@ static int mtk_eint_set_type(struct irq_data *d, unsigned int type)static int mtk_eint_irq_set_wake (struct irq_data *d,unsigned int on) {struct mtk_eint *eint =irq_data_get_irq_chip_data (d); -int shift = d->hwirq &0x1f ; -int reg = d->hwirq >>5 ; +unsigned int idx = eint->pins[d->hwirq].index; +unsigned int inst = eint->pins[d->hwirq].instance; +unsigned int shift = idx &0x1f ; +unsigned int port = idx >>5 ;if (on) - eint->wake_mask[reg] |=BIT (shift); + eint->wake_mask[inst][port] |=BIT (shift);else - eint->wake_mask[reg] &= ~BIT (shift); + eint->wake_mask[inst][port] &= ~BIT (shift);return 0 ; }static void mtk_eint_chip_write_mask (const struct mtk_eint *eint, -void __iomem *base,u32 *buf) +void __iomem *base,unsigned int **buf) { -int port; +int inst, port, port_num;void __iomem *reg; -for (port =0 ; port < eint->hw->ports; port++) { - reg = base + (port <<2 ); -writel_relaxed (~buf[port], reg + eint->regs->mask_set); -writel_relaxed (buf[port], reg + eint->regs->mask_clr); +for (inst =0 ; inst < eint->nbase; inst++) { + port_num =DIV_ROUND_UP (eint->base_pin_num[inst],32 ); +for (port =0 ; port < port_num; port++) { + reg = eint->base[inst] + (port <<2 ); +writel_relaxed (~buf[inst][port], reg + eint->regs->mask_set); +writel_relaxed (buf[inst][port], reg + eint->regs->mask_clr); + } } }
@@ -303,15 +313,18 @@ static struct irq_chip mtk_eint_irq_chip = {static unsigned int mtk_eint_hw_init (struct mtk_eint *eint) { -void __iomem *dom_en = eint->base + eint->regs->dom_en; -void __iomem *mask_set = eint->base + eint->regs->mask_set; -unsigned int i; - -for (i =0 ; i < eint->hw->ap_num; i +=32 ) { -writel (0xffffffff , dom_en); -writel (0xffffffff , mask_set); - dom_en +=4 ; - mask_set +=4 ; +void __iomem *dom_reg, *mask_reg; +unsigned int i, j; + +for (i =0 ; i < eint->nbase; i++) { + dom_reg = eint->base[i] + eint->regs->dom_en; + mask_reg = eint->base[i] + eint->regs->mask_set; +for (j =0 ; j < eint->base_pin_num[i]; j +=32 ) { +writel (0xffffffff , dom_reg); +writel (0xffffffff , mask_reg); + dom_reg +=4 ; + mask_reg +=4 ; + } }return 0 ;
@@ -322,14 +335,16 @@ mtk_eint_debounce_process(struct mtk_eint *eint, int index) {unsigned int rst, ctrl_offset;unsigned int bit, dbnc; +unsigned int inst = eint->pins[index].instance; +unsigned int idx = eint->pins[index].index; - ctrl_offset = (index /4 ) *4 + eint->regs->dbnc_ctrl; - dbnc =readl (eint->base + ctrl_offset); - bit =MTK_EINT_DBNC_SET_EN << ((index %4 ) *8 ); + ctrl_offset = (idx /4 ) *4 + eint->regs->dbnc_ctrl; + dbnc =readl (eint->base[inst] + ctrl_offset); + bit =MTK_EINT_DBNC_SET_EN << ((idx %4 ) *8 );if ((bit & dbnc) >0 ) { - ctrl_offset = (index /4 ) *4 + eint->regs->dbnc_set; - rst =MTK_EINT_DBNC_RST_BIT << ((index %4 ) *8 ); -writel (rst, eint->base + ctrl_offset); + ctrl_offset = (idx /4 ) *4 + eint->regs->dbnc_set; + rst =MTK_EINT_DBNC_RST_BIT << ((idx %4 ) *8 ); +writel (rst, eint->base[inst] + ctrl_offset); } }
@@ -337,65 +352,68 @@ static void mtk_eint_irq_handler(struct irq_desc *desc) {struct irq_chip *chip =irq_desc_get_chip (desc);struct mtk_eint *eint =irq_desc_get_handler_data (desc); -unsigned int status, eint_num; -int offset, mask_offset, index; -void __iomem *reg =mtk_eint_get_offset (eint,0 , eint->regs->stat); +unsigned int i, j, port, status, shift, mask, eint_num; +void __iomem *reg;int dual_edge, start_level, curr_level;chained_irq_enter (chip, desc); -for (eint_num =0 ; eint_num < eint->hw->ap_num; eint_num +=32 , - reg +=4 ) { - status =readl (reg); -while (status) { - offset =__ffs (status); - mask_offset = eint_num >>5 ; - index = eint_num + offset; - status &= ~BIT (offset); - -/* -* If we get an interrupt on pin that was only required -* for wake (but no real interrupt requested), mask the -* interrupt (as would mtk_eint_resume do anyway later -* in the resume sequence). -*/ -if (eint->wake_mask[mask_offset] &BIT (offset) && - !(eint->cur_mask[mask_offset] &BIT (offset))) { -writel_relaxed (BIT (offset), reg - - eint->regs->stat + - eint->regs->mask_set); - } - - dual_edge = eint->dual_edge[index]; -if (dual_edge) { -/* -* Clear soft-irq in case we raised it last -* time. -*/ -writel (BIT (offset), reg - eint->regs->stat + - eint->regs->soft_clr); - - start_level = - eint->gpio_xlate->get_gpio_state (eint->pctl, - index); - } - -generic_handle_domain_irq (eint->domain, index); - -if (dual_edge) { - curr_level =mtk_eint_flip_edge (eint, index); +for (i =0 ; i < eint->nbase; i++) { +for (j =0 ; j < eint->base_pin_num[i]; j +=32 ) { + port = j >>5 ; + status =readl (eint->base[i] + port *4 + eint->regs->stat); +while (status) { + shift =__ffs (status); + status &= ~BIT (shift); + mask =BIT (shift); + eint_num = eint->pin_list[i][shift + j];/* -* If level changed, we might lost one edge -* interrupt, raised it through soft-irq. +* If we get an interrupt on pin that was only required +* for wake (but no real interrupt requested), mask the +* interrupt (as would mtk_eint_resume do anyway later +* in the resume sequence). */ -if (start_level != curr_level) -writel (BIT (offset), reg - - eint->regs->stat + - eint->regs->soft_set); +if (eint->wake_mask[i][port] & mask && + !(eint->cur_mask[i][port] & mask)) { + reg =mtk_eint_get_offset (eint, eint_num, + eint->regs->mask_set); +writel_relaxed (mask, reg); + } + + dual_edge = eint->pins[eint_num].dual_edge; +if (dual_edge) { +/* +* Clear soft-irq in case we raised it last +* time. +*/ + reg =mtk_eint_get_offset (eint, eint_num, + eint->regs->soft_clr); +writel (mask, reg); + + start_level = + eint->gpio_xlate->get_gpio_state (eint->pctl, + eint_num); + } + +generic_handle_domain_irq (eint->domain, eint_num); + +if (dual_edge) { + curr_level =mtk_eint_flip_edge (eint, eint_num); + +/* +* If level changed, we might lost one edge +* interrupt, raised it through soft-irq. +*/ +if (start_level != curr_level) { + reg =mtk_eint_get_offset (eint, eint_num, + eint->regs->soft_set); +writel (mask, reg); + } + } + +if (eint->pins[eint_num].debounce) +mtk_eint_debounce_process (eint, eint_num); } - -if (index < eint->hw->db_cnt) -mtk_eint_debounce_process (eint, index); } }chained_irq_exit (chip, desc);
@@ -423,6 +441,8 @@ int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num,int virq, eint_offset;unsigned int set_offset, bit, clr_bit, clr_offset, rst, i, unmask, dbnc; +unsigned int inst = eint->pins[eint_num].instance; +unsigned int idx = eint->pins[eint_num].index;struct irq_data *d;if (!eint->hw->db_time)
@@ -432,8 +452,8 @@ int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num, eint_offset = (eint_num %4 ) *8 ; d =irq_get_irq_data (virq); - set_offset = (eint_num /4 ) *4 + eint->regs->dbnc_set; - clr_offset = (eint_num /4 ) *4 + eint->regs->dbnc_clr; + set_offset = (idx /4 ) *4 + eint->regs->dbnc_set; + clr_offset = (idx /4 ) *4 + eint->regs->dbnc_clr;if (!mtk_eint_can_en_debounce (eint, eint_num))return -EINVAL ;
@@ -454,12 +474,12 @@ int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num, } clr_bit =0xff << eint_offset; -writel (clr_bit, eint->base + clr_offset); +writel (clr_bit, eint->base[inst] + clr_offset); bit = ((dbnc <<MTK_EINT_DBNC_SET_DBNC_BITS ) |MTK_EINT_DBNC_SET_EN ) << eint_offset; rst =MTK_EINT_DBNC_RST_BIT << eint_offset; -writel (rst | bit, eint->base + set_offset); +writel (rst | bit, eint->base[inst] + set_offset);/* * Delay a while (more than 2T) to wait for hw debounce counter reset
@@ -487,32 +507,69 @@ EXPORT_SYMBOL_GPL(mtk_eint_find_irq);int mtk_eint_do_init (struct mtk_eint *eint) { -int i; +unsigned int size, i, port, inst =0 ; +struct mtk_pinctrl *hw = (struct mtk_pinctrl *)eint->pctl;/* If clients don't assign a specific regs, let's use generic one */ if (!eint->regs) eint->regs = &mtk_generic_eint_regs; - eint->wake_mask =devm_kcalloc (eint->dev, eint->hw->ports, -sizeof (*eint->wake_mask),GFP_KERNEL ); -if (!eint->wake_mask) + eint->base_pin_num =devm_kmalloc_array (eint->dev, eint->nbase,sizeof (u16), +GFP_KERNEL | __GFP_ZERO); +if (!eint->base_pin_num)return -ENOMEM ; - eint->cur_mask =devm_kcalloc (eint->dev, eint->hw->ports, -sizeof (*eint->cur_mask),GFP_KERNEL ); -if (!eint->cur_mask) -return -ENOMEM ; +if (eint->nbase ==1 ) { + size = eint->hw->ap_num *sizeof (struct mtk_eint_pin ); + eint->pins =devm_kmalloc (eint->dev, size,GFP_KERNEL ); +if (!eint->pins) + goto err_pins; + + eint->base_pin_num[inst] = eint->hw->ap_num; +for (i =0 ; i < eint->hw->ap_num; i++) { + eint->pins[i].instance = inst; + eint->pins[i].index = i; + eint->pins[i].debounce = (i < eint->hw->db_cnt) ?1 :0 ; + } + } - eint->dual_edge =devm_kcalloc (eint->dev, eint->hw->ap_num, -sizeof (int ),GFP_KERNEL ); -if (!eint->dual_edge) -return -ENOMEM ; +if (hw && hw->soc && hw->soc->eint_pin) { + eint->pins = hw->soc->eint_pin; +for (i =0 ; i < eint->hw->ap_num; i++) { + inst = eint->pins[i].instance; +if (inst >= eint->nbase) +continue ; + eint->base_pin_num[inst]++; + } + } + + eint->pin_list =devm_kmalloc (eint->dev, eint->nbase *sizeof (u16 *),GFP_KERNEL ); +if (!eint->pin_list) + goto err_pin_list; + + eint->wake_mask =devm_kmalloc (eint->dev, eint->nbase *sizeof (u32 *),GFP_KERNEL ); +if (!eint->wake_mask) + goto err_wake_mask; + + eint->cur_mask =devm_kmalloc (eint->dev, eint->nbase *sizeof (u32 *),GFP_KERNEL ); +if (!eint->cur_mask) + goto err_cur_mask; + +for (i =0 ; i < eint->nbase; i++) { + eint->pin_list[i] =devm_kzalloc (eint->dev, eint->base_pin_num[i] *sizeof (u16), +GFP_KERNEL ); + port =DIV_ROUND_UP (eint->base_pin_num[i],32 ); + eint->wake_mask[i] =devm_kzalloc (eint->dev, port *sizeof (u32),GFP_KERNEL ); + eint->cur_mask[i] =devm_kzalloc (eint->dev, port *sizeof (u32),GFP_KERNEL ); +if (!eint->pin_list[i] || !eint->wake_mask[i] || !eint->cur_mask[i]) + goto err_eint; + } eint->domain =irq_domain_add_linear (eint->dev->of_node, eint->hw->ap_num, &irq_domain_simple_ops,NULL );if (!eint->domain) -return -ENOMEM ; + goto err_eint;if (eint->hw->db_time) {for (i =0 ; i <MTK_EINT_DBNC_MAX ; i++)
@@ -523,8 +580,11 @@ int mtk_eint_do_init(struct mtk_eint *eint)mtk_eint_hw_init (eint);for (i =0 ; i < eint->hw->ap_num; i++) { + inst = eint->pins[i].instance; +if (inst >= eint->nbase) +continue ; + eint->pin_list[inst][eint->pins[i].index] = i;int virq =irq_create_mapping (eint->domain, i); -irq_set_chip_and_handler (virq, &mtk_eint_irq_chip, handle_level_irq);irq_set_chip_data (virq, eint);
@@ -534,6 +594,27 @@ int mtk_eint_do_init(struct mtk_eint *eint) eint);return 0 ; + +err_eint: +for (i =0 ; i < eint->nbase; i++) { +if (eint->cur_mask[i]) +devm_kfree (eint->dev, eint->cur_mask[i]); +if (eint->wake_mask[i]) +devm_kfree (eint->dev, eint->wake_mask[i]); +if (eint->pin_list[i]) +devm_kfree (eint->dev, eint->pin_list[i]); + } +devm_kfree (eint->dev, eint->cur_mask); +err_cur_mask: +devm_kfree (eint->dev, eint->wake_mask); +err_wake_mask: +devm_kfree (eint->dev, eint->pin_list); +err_pin_list: +if (eint->nbase ==1 ) +devm_kfree (eint->dev, eint->pins); +err_pins: +devm_kfree (eint->dev, eint->base_pin_num); +return -ENOMEM ; }EXPORT_SYMBOL_GPL (mtk_eint_do_init);
drivers/pinctrl/mediatek/mtk-eint.h +18 -5
@@ -1,10 +1,11 @@/* SPDX-License-Identifier: GPL-2.0 */ /* -* Copyright (C) 2014-2018 MediaTek Inc. +* Copyright (C) 2014-2025 MediaTek Inc. * * Author: Maoguang Meng <[email protected]> * Sean Wang <[email protected]> -* +* Hao Chang <[email protected]> +* Qingliang Li <[email protected]> */ #ifndef __MTK_EINT_H#define __MTK_EINT_H
@@ -40,6 +41,14 @@ struct mtk_eint_hw {const unsigned int *db_time; }; +struct mtk_eint_pin { +u16 number; +u8 instance; +u8 index; +bool debounce; +bool dual_edge; +}; +extern const unsigned int debounce_time_mt2701[];extern const unsigned int debounce_time_mt6765[];extern const unsigned int debounce_time_mt6795[];
@@ -56,17 +65,21 @@ struct mtk_eint_xt {struct mtk_eint {struct device *dev; -void __iomem *base; +void __iomem **base; +u8 nbase; +u16 *base_pin_num;struct irq_domain *domain;int irq;int *dual_edge; -u32 *wake_mask; -u32 *cur_mask; +u16 **pin_list; +u32 **wake_mask; +u32 **cur_mask;/* Used to fit into various EINT device */ const struct mtk_eint_hw *hw;const struct mtk_eint_regs *regs; +struct mtk_eint_pin *pins;u16 num_db_time;/* Used to fit into various pinctrl device */
drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c +31 -6
@@ -13,6 +13,7 @@#include <linux/platform_device.h> #include <linux/io.h> #include <linux/module.h> +#include <linux/of_address.h> #include <linux/of_irq.h> #include "mtk-eint.h"
@@ -367,7 +368,7 @@ static const struct mtk_eint_xt mtk_eint_xt = {int mtk_build_eint (struct mtk_pinctrl *hw,struct platform_device *pdev) {struct device_node *np = pdev->dev.of_node; -int ret; +int ret, i, j, count_reg_names;if (!IS_ENABLED (CONFIG_EINT_MTK ))return 0 ;
@@ -379,10 +380,24 @@ int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev)if (!hw->eint)return -ENOMEM ; - hw->eint->base =devm_platform_ioremap_resource_byname (pdev,"eint" ); -if (IS_ERR (hw->eint->base)) { - ret =PTR_ERR (hw->eint->base); - goto err_free_eint; + count_reg_names =of_property_count_strings (np,"reg-names" ); +if (count_reg_names < hw->soc->nbase_names) +return -EINVAL ; + + hw->eint->nbase = count_reg_names - hw->soc->nbase_names; + hw->eint->base =devm_kmalloc_array (&pdev->dev, hw->eint->nbase, +sizeof (*hw->eint->base),GFP_KERNEL | __GFP_ZERO); +if (!hw->eint->base) { + ret = -ENOMEM ; + goto err_free_base; + } + +for (i = hw->soc->nbase_names, j =0 ; i < count_reg_names; i++, j++) { + hw->eint->base[j] =of_iomap (np, i); +if (IS_ERR (hw->eint->base[j])) { + ret =PTR_ERR (hw->eint->base[j]); + goto err_free_eint; + } } hw->eint->irq =irq_of_parse_and_map (np,0 );
@@ -401,9 +416,19 @@ int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev) hw->eint->pctl = hw; hw->eint->gpio_xlate = &mtk_eint_xt; -return mtk_eint_do_init (hw->eint); + ret =mtk_eint_do_init (hw->eint); +if (ret) + goto err_free_eint; + +return 0 ; err_free_eint: +for (j =0 ; j < hw->eint->nbase; j++) { +if (hw->eint->base[j]) +iounmap (hw->eint->base[j]); + } +devm_kfree (hw->dev, hw->eint->base); +err_free_base:devm_kfree (hw->dev, hw->eint); hw->eint =NULL ;return ret;
drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h +1 -0
@@ -241,6 +241,7 @@ struct mtk_pin_soc {unsigned int nfuncs;const struct mtk_eint_regs *eint_regs;const struct mtk_eint_hw *eint_hw; +struct mtk_eint_pin *eint_pin;/* Specific parameters per SoC */ u8 gpio_m;
drivers/pinctrl/mediatek/pinctrl-paris.h +7 -0
@@ -49,6 +49,13 @@ __VA_ARGS__, { } }, \ } +#define MTK_EINT_PIN (_number, _instance, _index, _debounce) { \ + .number = _number, \ + .instance = _instance, \ + .index = _index, \ + .debounce = _debounce, \ + } +#define PINCTRL_PIN_GROUP (_name_, id) \ { \ .grp = PINCTRL_PINGROUP(_name_,id##_pins, ARRAY_SIZE(id##_pins)), \
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 688/1376 pinctrl: mediatek: Fix the invalid conditions
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hao Chang <[email protected]>
[ Upstream commit 86dee87f4b2e6ac119b03810e58723d0b27787a4 ]
The variable count_reg_names is defined as an int type and cannot be directly compared to an unsigned int. To resolve this issue, first verify the correctness of count_reg_names.
Stable-dep-of: 88292b7103d2 ("pinctrl: mediatek: free EINT resources on unbind")
--- drivers/pinctrl/mediatek/mtk-eint.c | 4 ++-- drivers/pinctrl/mediatek/mtk-eint.h | 2 +- drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c | 7 +++++-- 3 files changed, 8 insertions(+), 5 deletions(-)
drivers/pinctrl/mediatek/mtk-eint.c +2 -2
@@ -507,7 +507,7 @@ EXPORT_SYMBOL_GPL(mtk_eint_find_irq);int mtk_eint_do_init (struct mtk_eint *eint) { -unsigned int size, i, port, inst =0 ; +unsigned int size, i, port, virq, inst =0 ;struct mtk_pinctrl *hw = (struct mtk_pinctrl *)eint->pctl;/* If clients don't assign a specific regs, let's use generic one */
@@ -584,7 +584,7 @@ int mtk_eint_do_init(struct mtk_eint *eint)if (inst >= eint->nbase)continue ; eint->pin_list[inst][eint->pins[i].index] = i; -int virq =irq_create_mapping (eint->domain, i); + virq =irq_create_mapping (eint->domain, i);irq_set_chip_and_handler (virq, &mtk_eint_irq_chip, handle_level_irq);irq_set_chip_data (virq, eint);
drivers/pinctrl/mediatek/mtk-eint.h +1 -1
@@ -66,7 +66,7 @@ struct mtk_eint_xt {struct mtk_eint {struct device *dev;void __iomem **base; -u8 nbase; +int nbase;u16 *base_pin_num;struct irq_domain *domain;int irq;
drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c +5 -2
@@ -381,10 +381,13 @@ int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev)return -ENOMEM ; count_reg_names =of_property_count_strings (np,"reg-names" ); -if (count_reg_names < hw->soc->nbase_names) +if (count_reg_names <0 ) +return -EINVAL ; + + hw->eint->nbase = count_reg_names - (int )hw->soc->nbase_names; +if (hw->eint->nbase <=0 )return -EINVAL ; - hw->eint->nbase = count_reg_names - hw->soc->nbase_names; hw->eint->base =devm_kmalloc_array (&pdev->dev, hw->eint->nbase,sizeof (*hw->eint->base),GFP_KERNEL | __GFP_ZERO);if (!hw->eint->base) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 689/1376 pinctrl: mediatek: eint: Fix invalid pointer dereference for v1 platforms
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nícolas F. R. A. Prado <[email protected]>
[ Upstream commit 1c9977b263475373b31bbf86af94a5c9ae2be42c ]
Commit 3ef9f710efcb ("pinctrl: mediatek: Add EINT support for multiple addresses") introduced an access to the 'soc' field of struct mtk_pinctrl in mtk_eint_do_init() and for that an include of pinctrl-mtk-common-v2.h.
However, pinctrl drivers relying on the v1 common driver include pinctrl-mtk-common.h instead, which provides another definition of struct mtk_pinctrl that does not contain an 'soc' field.
Since mtk_eint_do_init() can be called both by v1 and v2 drivers, it will now try to dereference an invalid pointer when called on v1 platforms. This has been observed on Genio 350 EVK (MT8365), which crashes very early in boot (the kernel trace can only be seen with earlycon).
In order to fix this, since 'struct mtk_pinctrl' was only needed to get a 'struct mtk_eint_pin', make 'struct mtk_eint_pin' a parameter of mtk_eint_do_init() so that callers need to supply it, removing mtk_eint_do_init()'s dependency on any particular 'struct mtk_pinctrl'.
Stable-dep-of: 88292b7103d2 ("pinctrl: mediatek: free EINT resources on unbind")
--- drivers/pinctrl/mediatek/mtk-eint.c | 26 ++++++++----------- drivers/pinctrl/mediatek/mtk-eint.h | 5 ++-- .../pinctrl/mediatek/pinctrl-mtk-common-v2.c | 2 +- drivers/pinctrl/mediatek/pinctrl-mtk-common.c | 2 +- 4 files changed, 16 insertions(+), 19 deletions(-)
drivers/pinctrl/mediatek/mtk-eint.c +11 -15
@@ -22,7 +22,6 @@#include <linux/platform_device.h> #include "mtk-eint.h" -#include "pinctrl-mtk-common-v2.h" #define MTK_EINT_EDGE_SENSITIVE 0#define MTK_EINT_LEVEL_SENSITIVE 1
@@ -505,10 +504,9 @@ int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n) }EXPORT_SYMBOL_GPL (mtk_eint_find_irq); -int mtk_eint_do_init (struct mtk_eint *eint) +int mtk_eint_do_init (struct mtk_eint *eint,struct mtk_eint_pin *eint_pin) {unsigned int size, i, port, virq, inst =0 ; -struct mtk_pinctrl *hw = (struct mtk_pinctrl *)eint->pctl;/* If clients don't assign a specific regs, let's use generic one */ if (!eint->regs)
@@ -519,7 +517,15 @@ int mtk_eint_do_init(struct mtk_eint *eint)if (!eint->base_pin_num)return -ENOMEM ; -if (eint->nbase ==1 ) { +if (eint_pin) { + eint->pins = eint_pin; +for (i =0 ; i < eint->hw->ap_num; i++) { + inst = eint->pins[i].instance; +if (inst >= eint->nbase) +continue ; + eint->base_pin_num[inst]++; + } + }else { size = eint->hw->ap_num *sizeof (struct mtk_eint_pin ); eint->pins =devm_kmalloc (eint->dev, size,GFP_KERNEL );if (!eint->pins)
@@ -533,16 +539,6 @@ int mtk_eint_do_init(struct mtk_eint *eint) } } -if (hw && hw->soc && hw->soc->eint_pin) { - eint->pins = hw->soc->eint_pin; -for (i =0 ; i < eint->hw->ap_num; i++) { - inst = eint->pins[i].instance; -if (inst >= eint->nbase) -continue ; - eint->base_pin_num[inst]++; - } - } - eint->pin_list =devm_kmalloc (eint->dev, eint->nbase *sizeof (u16 *),GFP_KERNEL );if (!eint->pin_list) goto err_pin_list;
@@ -610,7 +606,7 @@ int mtk_eint_do_init(struct mtk_eint *eint) err_wake_mask:devm_kfree (eint->dev, eint->pin_list); err_pin_list: -if (eint->nbase ==1 ) +if (!eint_pin)devm_kfree (eint->dev, eint->pins); err_pins:devm_kfree (eint->dev, eint->base_pin_num);
drivers/pinctrl/mediatek/mtk-eint.h +3 -2
@@ -88,7 +88,7 @@ struct mtk_eint { };#if IS_ENABLED (CONFIG_EINT_MTK ) -int mtk_eint_do_init (struct mtk_eint *eint); +int mtk_eint_do_init (struct mtk_eint *eint,struct mtk_eint_pin *eint_pin);int mtk_eint_do_suspend (struct mtk_eint *eint);int mtk_eint_do_resume (struct mtk_eint *eint); int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_n,
@@ -96,7 +96,8 @@ int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_n,int mtk_eint_find_irq (struct mtk_eint *eint,unsigned long eint_n);#else -static inline int mtk_eint_do_init (struct mtk_eint *eint) +static inline int mtk_eint_do_init (struct mtk_eint *eint, +struct mtk_eint_pin *eint_pin) {return -EOPNOTSUPP ; }
drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c +1 -1
@@ -419,7 +419,7 @@ int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev) hw->eint->pctl = hw; hw->eint->gpio_xlate = &mtk_eint_xt; - ret =mtk_eint_do_init (hw->eint); + ret =mtk_eint_do_init (hw->eint, hw->soc->eint_pin);if (ret) goto err_free_eint;
drivers/pinctrl/mediatek/pinctrl-mtk-common.c +1 -1
@@ -1033,7 +1033,7 @@ static int mtk_eint_init(struct mtk_pinctrl *pctl, struct platform_device *pdev) pctl->eint->pctl = pctl; pctl->eint->gpio_xlate = &mtk_eint_xt; -return mtk_eint_do_init (pctl->eint); +return mtk_eint_do_init (pctl->eint,NULL ); }/* This is used as a common probe function */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 690/1376 pinctrl: mediatek: free EINT resources on unbind
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Justin Yeh <[email protected]>
[ Upstream commit 88292b7103d260e3e606eb3bb2794060a5fde48e ]
mtk_eint_do_init() creates an IRQ domain, populates it with a mapping for every EINT line and installs a chained handler on the parent interrupt, but none of these are ever released. This was harmless while the drivers were built-in, but now that they can be built as modules and unbound/rmmod'd it leaves behind a dangling IRQ domain, interrupt mappings whose chip data points at freed memory, and a chained handler that keeps firing into that freed data.
The plain allocations in mtk_eint_do_init() already use the device-managed devm_*() helpers, so tear the remaining resources down the same way:
register a devm action that detaches the chained handler, waits for any in-flight handler to finish, disposes of the per-line mappings and removes the IRQ domain. This mirrors the device-managed lifecycle adopted for the GPIO chip and keeps the whole EINT setup self-cleaning on unbind.
--- drivers/pinctrl/mediatek/mtk-eint.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-)
drivers/pinctrl/mediatek/mtk-eint.c +24 -1
@@ -12,8 +12,10 @@*/ #include <linux/delay.h> +#include <linux/device.h> #include <linux/err.h> #include <linux/gpio/driver.h> +#include <linux/interrupt.h> #include <linux/io.h> #include <linux/irqchip/chained_irq.h> #include <linux/irqdomain.h>
@@ -504,6 +506,27 @@ int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n) }EXPORT_SYMBOL_GPL (mtk_eint_find_irq); +static void mtk_eint_teardown (void *data) +{ +struct mtk_eint *eint = data; +unsigned int i, virq; + +/* Detach the demux handler so it can no longer reference freed data. */ +irq_set_chained_handler_and_data (eint->irq,NULL ,NULL ); + +/* Wait for any in-flight handler to finish before tearing down. */ +synchronize_irq (eint->irq); + +/* Dispose of all child mappings before the domain is removed. */ +for (i =0 ; i < eint->hw->ap_num; i++) { + virq =irq_find_mapping (eint->domain, i); +if (virq) +irq_dispose_mapping (virq); + } + +irq_domain_remove (eint->domain); +} +int mtk_eint_do_init (struct mtk_eint *eint,struct mtk_eint_pin *eint_pin) {unsigned int size, i, port, virq, inst =0 ;
@@ -589,7 +612,7 @@ int mtk_eint_do_init(struct mtk_eint *eint, struct mtk_eint_pin *eint_pin)irq_set_chained_handler_and_data (eint->irq, mtk_eint_irq_handler, eint); -return 0 ; +return devm_add_action_or_reset (eint->dev, mtk_eint_teardown, eint); err_eint:for (i =0 ; i < eint->nbase; i++) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 691/1376 tools/build: Add bpftool-skeletons feature test
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tomas Glozar <[email protected]>
[ Upstream commit 8a635c3856ddb74ed3fe7c856b271cdfeb65f293 ]
Add bpftool-skeletons feature test, testing the presence of a bpftool capable of generating skeletons.
This is to be used for tools that do not require building their own bootstrap bpftool from the kernel source tree.
Stable-dep-of: d5a1d1270c89 ("tools/build: Allow versioning of all LLVM tools defined in Makefile.include")
--- tools/build/Makefile.feature | 3 ++- tools/build/feature/Makefile | 3 +++ tools/scripts/Makefile.include | 3 +++ 3 files changed, 8 insertions(+), 1 deletion(-)
tools/build/Makefile.feature +2 -1
@@ -110,7 +110,8 @@ FEATURE_TESTS_EXTRA := \ libbpf-bpf_create_map \ libpfm4 \ libdebuginfod \ - clang-bpf-co-re + clang-bpf-co-re \ + bpftool-skeletons FEATURE_TESTS ?= $(FEATURE_TESTS_BASIC)
tools/build/feature/Makefile +3 -0
@@ -426,6 +426,9 @@ $(OUTPUT)test-file-handle.bin: $(OUTPUT)test-libpfm4.bin: $(BUILD) -lpfm +$(OUTPUT)test-bpftool-skeletons.bin: + $(BPFTOOL) version | grep '^features:.*skeletons' \ + > $(@:.bin=.make.output) 2>&1 ############################### clean:
tools/scripts/Makefile.include +3 -0
@@ -91,6 +91,9 @@ LLVM_CONFIG ?= llvm-config LLVM_OBJCOPY ?= llvm-objcopy LLVM_STRIP ?= llvm-strip +# Some tools require bpftool +BPFTOOL ?= bpftool + ifeq ($(CC_NO_CLANG), 1) EXTRA_WARNINGS += -Wstrict-aliasing=3
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 692/1376 tools/build: Allow versioning of all LLVM tools defined in Makefile.include
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Clark <[email protected]>
[ Upstream commit d5a1d1270c898057afc5b51fb6d0f2defa89d56d ]
The version of LLVM tools can be given on the build command with LLVM=-15, but this isn't applied to all tools. For example $(CC) gets versioned, but $(CLANG) doesn't. This causes a Perf build with LTO=1 to fail with an error about mixed clang versions:
ld.lld: error: libperf/core.o: Unknown attribute kind (86)
(Producer: 'LLVM18.1.8' Reader: 'LLVM 15.0.7')
This file has two "ifneq ($(LLVM),)" blocks adjacent to each other, so merge these blocks making it obvious that all tools should be versioned consistently and there is nothing special about each block.
This also reveals that ?= and "allow-override" are used inconsistently between the blocks. "allow-override" is technically only required for builtin variables, but isn't only used on them, and doesn't do any harm if used on a non-builtin. Make them all "allow-override" for consistency. The only functional difference this will cause is if there is a file level definition of one of the variables followed by an "#include of Makefile.include" which will now overwrite. But this isn't done and in a later commit some of the duplicate definitions will be removed for good measure.
There are also some other LLVM tools that are not defined here and will be moved in a later commit.
--- tools/scripts/Makefile.include | 37 ++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 17 deletions(-)
tools/scripts/Makefile.include +20 -17
@@ -59,10 +59,18 @@ LLVM_SUFFIX := $(LLVM) endif $(call allow-override,CC,$(LLVM_PREFIX)clang$(LLVM_SUFFIX)) +$(call allow-override,CLANG,$(LLVM_PREFIX)clang$(LLVM_SUFFIX)) +$(call allow-override,HOSTCC,$(LLVM_PREFIX)clang$(LLVM_SUFFIX)) $(call allow-override,AR,$(LLVM_PREFIX)llvm-ar$(LLVM_SUFFIX)) +$(call allow-override,HOSTAR,$(LLVM_PREFIX)llvm-ar$(LLVM_SUFFIX)) $(call allow-override,LD,$(LLVM_PREFIX)ld.lld$(LLVM_SUFFIX)) +$(call allow-override,HOSTLD,$(LLVM_PREFIX)ld.lld$(LLVM_SUFFIX)) $(call allow-override,CXX,$(LLVM_PREFIX)clang++$(LLVM_SUFFIX)) $(call allow-override,STRIP,$(LLVM_PREFIX)llvm-strip$(LLVM_SUFFIX)) +$(call allow-override,LLVM_STRIP,$(LLVM_PREFIX)llvm-strip$(LLVM_SUFFIX)) +$(call allow-override,LLC,$(LLVM_PREFIX)llc$(LLVM_SUFFIX)) +$(call allow-override,LLVM_CONFIG,$(LLVM_PREFIX)llvm-config$(LLVM_SUFFIX)) +$(call allow-override,LLVM_OBJCOPY,$(LLVM_PREFIX)llvm-objcopy$(LLVM_SUFFIX)) else # Allow setting various cross-compile vars or setting CROSS_COMPILE as a prefix. $(call allow-override,CC,$(CROSS_COMPILE)gcc)
@@ -70,26 +78,21 @@ $(call allow-override,AR,$(CROSS_COMPILE)ar) $(call allow-override,LD,$(CROSS_COMPILE)ld) $(call allow-override,CXX,$(CROSS_COMPILE)g++) $(call allow-override,STRIP,$(CROSS_COMPILE)strip) -endif - -CC_NO_CLANG := $(shell $(CC) -dM -E -x c /dev/null | grep -Fq "__clang__"; echo $$?) -ifneq ($(LLVM),) -HOSTAR ?= $(LLVM_PREFIX)llvm-ar$(LLVM_SUFFIX) -HOSTCC ?= $(LLVM_PREFIX)clang$(LLVM_SUFFIX) -HOSTLD ?= $(LLVM_PREFIX)ld.lld$(LLVM_SUFFIX) -else -HOSTAR ?= ar -HOSTCC ?= gcc -HOSTLD ?= ld +# Host versions aren't prefixed +$(call allow-override,HOSTAR,ar) +$(call allow-override,HOSTCC,gcc) +$(call allow-override,HOSTLD,ld) + +# Some tools still require Clang, LLC and/or LLVM utils +$(call allow-override,CLANG,clang) +$(call allow-override,LLC,llc) +$(call allow-override,LLVM_CONFIG,llvm-config) +$(call allow-override,LLVM_OBJCOPY,llvm-objcopy) +$(call allow-override,LLVM_STRIP,llvm-strip) endif -# Some tools require Clang, LLC and/or LLVM utils -CLANG ?= clang -LLC ?= llc -LLVM_CONFIG ?= llvm-config -LLVM_OBJCOPY ?= llvm-objcopy -LLVM_STRIP ?= llvm-strip +CC_NO_CLANG := $(shell $(CC) -dM -E -x c /dev/null | grep -Fq "__clang__"; echo $$?) # Some tools require bpftool BPFTOOL ?= bpftool
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 693/1376 power: supply: sbs-battery: Use a per-device serial number buffer
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Babanpreet Singh <[email protected]>
[ Upstream commit 6027892925b8d19d2245c2d077e2ae35b49cc2b1 ]
sbs_get_battery_serial_number() formats the battery serial number into sbs_serial[], a single file-scope buffer shared by every sbs-battery instance, and points val->strval at it.
Nothing restricts this driver to one instance. It binds per I2C client, and sbs-manager registers one muxed I2C channel per supported battery specifically so that the smart battery driver can be bound to each of them, so several sbs-battery instances on one system is a supported configuration.
The power supply core reads strval after the driver's get_property() callback has returned: power_supply_show_property() fills a local union power_supply_propval, then formats it with sysfs_emit(). Two concurrent POWER_SUPPLY_PROP_SERIAL_NUMBER reads on different batteries therefore race for the shared buffer - battery B's sprintf() can land between battery A filling the buffer and the core reading it, and battery A then reports battery B's serial number.
Move the buffer into struct sbs_info so that each battery formats into its own storage. It is deliberately not added to the chip->strings[]
array: those entries hold the cached constant strings that sbs_invalidate_cached_props() clears on presence changes, whereas the serial number is re-read from its word register on every access.
--- drivers/power/supply/sbs-battery.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/power/supply/sbs-battery.c +4 -3
@@ -216,6 +216,7 @@ struct sbs_info {u32 flags;int technology;char strings[NR_STRING_BUFFERS ][I2C_SMBUS_BLOCK_MAX +1 ]; +char serial[5 ]; }; static char *sbs_get_string_buf(struct sbs_info *chip,
@@ -820,18 +821,18 @@ static int sbs_get_battery_capacity(struct i2c_client *client,return 0 ; } -static char sbs_serial[5 ];static int sbs_get_battery_serial_number (struct i2c_client *client,union power_supply_propval *val) { +struct sbs_info *chip =i2c_get_clientdata (client);int ret; ret =sbs_read_word_data (client, sbs_data[REG_SERIAL_NUMBER ].addr);if (ret <0 )return ret; -sprintf (sbs_serial,"%04x" , ret); - val->strval = sbs_serial; +sprintf (chip->serial,"%04x" , ret); + val->strval = chip->serial;return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 694/1376 scsi: ufs: debugfs: Reserve space for a string terminator
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Li Qiang <[email protected]>
[ Upstream commit abd26e6b53c4169122d61fdd4cabe09bdd916aac ]
ufs_saved_err_write() copies user input into a zero-initialized stack buffer and passes it to kstrtoint(). A write that fills the entire buffer overwrites its only terminator.
Reject an input whose length leaves no room for the trailing NUL.
--- drivers/ufs/core/ufs-debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/ufs/core/ufs-debugfs.c +1 -1
@@ -165,7 +165,7 @@ static ssize_t ufs_saved_err_write(struct file *file, const char __user *buf,char val_str[16 ] = { };int val, ret; -if (count >sizeof (val_str)) +if (count >=sizeof (val_str))return -EINVAL ;if (copy_from_user (val_str, buf, count))return -EFAULT ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 695/1376 crypto: keembay - Initialize completion before requesting IRQ
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linmao Li <[email protected]>
[ Upstream commit fce20289dd622cc7ab78d72c8a979a9f8b7cb10e ]
kmb_ocs_aes_probe() requests the device IRQ before initializing irq_completion. Once the handler is registered it can run immediately, and ocs_aes_irq_handler() unconditionally calls complete(). An interrupt in this window would therefore use an uninitialized completion.
Initialize the completion before requesting the IRQ, as the sibling OCS HCU and ECC drivers already do.
--- drivers/crypto/intel/keembay/keembay-ocs-aes-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/crypto/intel/keembay/keembay-ocs-aes-core.c +2 -2
@@ -1602,6 +1602,8 @@ static int kmb_ocs_aes_probe(struct platform_device *pdev)if (IS_ERR (aes_dev->base_reg))return PTR_ERR (aes_dev->base_reg); +init_completion (&aes_dev->irq_completion); +/* Get and request IRQ */ aes_dev->irq =platform_get_irq (pdev,0 );if (aes_dev->irq <0 )
@@ -1619,8 +1621,6 @@ static int kmb_ocs_aes_probe(struct platform_device *pdev)list_add_tail (&aes_dev->list, &ocs_aes.dev_list);spin_unlock (&ocs_aes.lock); -init_completion (&aes_dev->irq_completion); -/* Initialize crypto engine */ aes_dev->engine =crypto_engine_alloc_init (dev, true);if (!aes_dev->engine) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 696/1376 crypto: keembay - publish OF module alias for OCS AES/SM4
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Can Peng <[email protected]>
[ Upstream commit 0a94091e29f914e4f233a208599ca4055882c01b ]
The Keem Bay OCS AES/SM4 driver has an OF match table wired to .of_match_table, but does not export the table with MODULE_DEVICE_TABLE().
Although the match table lives in keembay-ocs-aes-core.o, that object is part of the composite keembay-ocs-aes module. Add the missing MODULE_DEVICE_TABLE(of, ...) entry so modpost can generate OF module alias information for OF based module autoloading.
This is a source-level fix. It does not claim dynamic hardware reproduction; the evidence is the driver-owned match table, its use by the platform driver, and the missing module alias publication.
--- drivers/crypto/intel/keembay/keembay-ocs-aes-core.c | 1 + 1 file changed, 1 insertion(+)
drivers/crypto/intel/keembay/keembay-ocs-aes-core.c +1 -0
@@ -1561,6 +1561,7 @@ static const struct of_device_id kmb_ocs_aes_of_match[] = { }, {} }; +MODULE_DEVICE_TABLE (of, kmb_ocs_aes_of_match);static void kmb_ocs_aes_remove (struct platform_device *pdev) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 697/1376 RDMA/mlx5: Fix integer overflow of user QP buffer size
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maher Sanalla <[email protected]>
[ Upstream commit dec47e4b0fe34afdf38caa72b4408ba95502e5de ]
set_user_buf_size() computes the QP buffer size by left-shifting the user-supplied rq.wqe_cnt and rq.wqe_shift values as signed integers. A sufficiently large rq.wqe_cnt causes signed integer overflow, which is undefined behavior, and yields a small or negative buf_size, causing ib_umem_get() to map a buffer smaller than the hardware will actually write into.
Replace the shifts and addition with check_shl_overflow() and check_add_overflow(), rejecting invalid user inputs.
Moreover, guard the identical shift computing qp->sq.offset in _create_user_qp() before set_user_buf_size() is reached.
--- drivers/infiniband/hw/mlx5/qp.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-)
drivers/infiniband/hw/mlx5/qp.c +20 -5
@@ -637,6 +637,7 @@ static int set_user_buf_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr) {int desc_sz =1 << qp->sq.wqe_shift; +int rq_buf_size, sq_buf_size;if (desc_sz >MLX5_CAP_GEN (dev->mdev, max_wqe_sz_sq)) { mlx5_ib_warn(dev, "desc_sz %d, max_sq_desc_sz %d\n",
@@ -661,11 +662,21 @@ static int set_user_buf_size(struct mlx5_ib_dev *dev,if (attr->qp_type ==IB_QPT_RAW_PACKET || qp->flags &IB_QP_CREATE_SOURCE_QPN ) { - base->ubuffer.buf_size = qp->rq.wqe_cnt << qp->rq.wqe_shift; - qp->raw_packet_qp.sq.ubuffer.buf_size = qp->sq.wqe_cnt <<6 ; +if (check_shl_overflow (qp->rq.wqe_cnt, qp->rq.wqe_shift, + &base->ubuffer.buf_size)) +return -EINVAL ; +if (check_shl_overflow (qp->sq.wqe_cnt,6 , + &qp->raw_packet_qp.sq.ubuffer.buf_size)) +return -EINVAL ; }else { - base->ubuffer.buf_size = (qp->rq.wqe_cnt << qp->rq.wqe_shift) + - (qp->sq.wqe_cnt <<6 ); +if (check_shl_overflow (qp->rq.wqe_cnt, qp->rq.wqe_shift, + &rq_buf_size)) +return -EINVAL ; +if (check_shl_overflow (qp->sq.wqe_cnt,6 , &sq_buf_size)) +return -EINVAL ; +if (check_add_overflow (rq_buf_size, sq_buf_size, + &base->ubuffer.buf_size)) +return -EINVAL ; }return 0 ;
@@ -989,7 +1000,11 @@ static int _create_user_qp(struct mlx5_ib_dev *dev, struct ib_pd *pd, qp->rq.offset =0 ; qp->sq.wqe_shift =ilog2 (MLX5_SEND_WQE_BB ); - qp->sq.offset = qp->rq.wqe_cnt << qp->rq.wqe_shift; +if (check_shl_overflow (qp->rq.wqe_cnt, qp->rq.wqe_shift, + &qp->sq.offset)) { + err = -EINVAL ; + goto err_bfreg; + } err =set_user_buf_size (dev, qp, ucmd, base, attr);if (err)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 698/1376 powercap: intel_rapl_tpmi: Handle PMU registration failure during probe
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sumeet Pawnikar <[email protected]>
[ Upstream commit 9229916d59918ec9d3639e7263e1e97be638e361 ]
intel_rapl_tpmi_probe() invokes rapl_package_add_pmu() but ignores its return value, so a PMU registration failure would leave the driver reporting probe success despite the PMU being absent, with no log trace.
Since PMU registration is an optional auxiliary feature for perf energy counters, its failure should not break the primary powercap functionality. Check the return value and log a warning to ensure graceful degradation.
--- drivers/powercap/intel_rapl_tpmi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/powercap/intel_rapl_tpmi.c +4 -1
@@ -313,7 +313,10 @@ static int intel_rapl_tpmi_probe(struct auxiliary_device *auxdev, goto err; } -rapl_package_add_pmu (trp->rp); + ret =rapl_package_add_pmu (trp->rp); +if (ret) +dev_info (&auxdev->dev,"Failed to add RAPL PMU for Package%d, %d\n" , + info->package_id, ret);auxiliary_set_drvdata (auxdev, trp);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 699/1376 isofs: release zisofs block pointer buffer head
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yichong Chen <[email protected]>
[ Upstream commit 2f7dd9b86fe4076059e6a4a2a2c5d565afd76b9e ]
zisofs_fill_pages() reads the compressed block pointer table. The error paths release the current buffer_head, the loop also releases the old buffer_head when it advances. However, the success path leaves the last buffer_head referenced. Release it before returning success.
--- fs/isofs/compress.c | 1 + 1 file changed, 1 insertion(+)
fs/isofs/compress.c +1 -0
@@ -293,6 +293,7 @@ static int zisofs_fill_pages(struct inode *inode, int full_page, int pcount,memzero_page (*pages, poffset,PAGE_SIZE - poffset);SetPageUptodate (*pages); } +brelse (bh);return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 700/1376 spi: oc-tiny: switch to managed controller allocation
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
[ Upstream commit d710f43ce30975d197f73c543bfe47b958d8ba17 ]
The controller is allocated with the non-managed spi_alloc_host() while the interrupt is registered with devm_request_irq(). During removal, spi_bitbang_stop() only unregisters the controller; the subsequent spi_controller_put() then frees the controller together with its embedded driver-private devdata, which is the IRQ handler's dev_id. The devm_request_irq() release action (free_irq()), which drains the handler, does not run until after .remove() returns. A late or latched interrupt can therefore reach tiny_spi_irq() and dereference already-freed memory (e.g. hw->base).
Switch to devm_spi_alloc_host() so that the devres LIFO order releases the controller only after free_irq() has drained the handler, and drop the now-redundant spi_controller_put() from .remove(). The probe error path is simplified to direct returns.
This issue was found by an in-house static analysis tool.
--- drivers/spi/spi-oc-tiny.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-)
drivers/spi/spi-oc-tiny.c +8 -16
@@ -211,11 +211,11 @@ static int tiny_spi_probe(struct platform_device *pdev)struct tiny_spi_platform_data *platp =dev_get_platdata (&pdev->dev);struct tiny_spi *hw;struct spi_controller *host; -int err = -ENODEV ; +int err; - host =spi_alloc_host (&pdev->dev,sizeof (struct tiny_spi )); + host =devm_spi_alloc_host (&pdev->dev,sizeof (struct tiny_spi ));if (!host) -return err; +return -ENOMEM ;/* setup the host state. */ host->bus_num = pdev->id;
@@ -233,10 +233,8 @@ static int tiny_spi_probe(struct platform_device *pdev)/* find and map our resources */ hw->base =devm_platform_ioremap_resource (pdev,0 ); -if (IS_ERR (hw->base)) { - err =PTR_ERR (hw->base); - goto exit; - } +if (IS_ERR (hw->base)) +return PTR_ERR (hw->base);/* irq is optional */ hw->irq =platform_get_irq (pdev,0 );if (hw->irq >=0 ) {
@@ -244,7 +242,7 @@ static int tiny_spi_probe(struct platform_device *pdev) err =devm_request_irq (&pdev->dev, hw->irq, tiny_spi_irq,0 , pdev->name, hw);if (err) - goto exit; +return err; }/* find platform data */ if (platp) {
@@ -253,29 +251,23 @@ static int tiny_spi_probe(struct platform_device *pdev) }else { err =tiny_spi_of_probe (pdev);if (err) - goto exit; +return err; }/* register our spi controller */ err =spi_bitbang_start (&hw->bitbang);if (err) - goto exit; +return err;dev_info (&pdev->dev,"base %p, irq %d\n" , hw->base, hw->irq);return 0 ; - -exit: -spi_controller_put (host); -return err; }static void tiny_spi_remove (struct platform_device *pdev) {struct tiny_spi *hw =platform_get_drvdata (pdev); -struct spi_controller *host = hw->bitbang.ctlr;spi_bitbang_stop (&hw->bitbang); -spi_controller_put (host); }#ifdef CONFIG_OF
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 701/1376 w1: ds2482: Fix signedness bug in ds2482_w1_triplet()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Babanpreet Singh <[email protected]>
[ Upstream commit 4d3721b204f961e905714954ff95633337b768e3 ]
ds2482_wait_1wire_idle() returns the status register value (0..255) on success, or a negative value on I2C failure: -1 when selecting the status register fails, or a negative errno from i2c_smbus_read_byte().
ds2482_w1_triplet() feeds that result into "return (status >> 5);" without checking for errors, and the function returns u8. For a negative status the arithmetic shift keeps the sign and the u8 truncation fabricates a triplet result whose meaning depends on the errno value: -1 and -EIO happen to become 0xff, whose set low bits make w1_search() abort, but -ETIMEDOUT (-110 >> 5 = -4) becomes 0xfc - "devices responded on both branches, wrote 1" - and -EOPNOTSUPP (-95 >> 5 = -3) becomes 0xfd - "only the zero branch responded". w1_search() then continues the ROM search with a fabricated direction bit instead of aborting, and the corrupted id is either rejected by the ROM CRC (existing device missed) or registers a phantom slave.
The function already defines an in-band error value: status is initialized to (3 << 5), which decodes to 3 (both branch bits set, "no device responded") and makes w1_search() terminate the search when sending the triplet command fails. Decode a negative status to the same value.
Found by smatch:drivers/w1/masters/ds2482.c:314 ds2482_w1_triplet() warn: signedness bug returning '(-67108864)'
--- drivers/w1/masters/ds2482.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/w1/masters/ds2482.c +4 -0
@@ -309,6 +309,10 @@ static u8 ds2482_w1_triplet(void *data, u8 dbit)mutex_unlock (&pdev->access_lock); +/* On bus error, decode to 3 (no device responded) to abort the search */ +if (status <0 ) + status =3 <<5 ; +/* Decode the status */ return (status >>5 ); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 702/1376 remoteproc: core: Drop redundant initialization of ret in rproc_shutdown()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peng Fan <[email protected]>
[ Upstream commit 4531b6bad5af669511c348ad5225d9f697af221b ]
The variable ret is immediately assigned the return value of mutex_lock_interruptible(), making its prior initialization to zero unnecessary. Remove the redundant assignment
No functional changes.
Stable-dep-of: 2482ca875ef5 ("remoteproc: Allow shutdown of crashed processors")
--- drivers/remoteproc/remoteproc_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/remoteproc/remoteproc_core.c +1 -1
@@ -1989,7 +1989,7 @@ EXPORT_SYMBOL(rproc_boot);int rproc_shutdown (struct rproc *rproc) {struct device *dev = &rproc->dev; -int ret =0 ; +int ret; ret =mutex_lock_interruptible (&rproc->lock);if (ret) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 703/1376 remoteproc: Allow shutdown of crashed processors
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bjorn Andersson <[email protected]>
[ Upstream commit 2482ca875ef5993df8daee563033d70e2523a25f ]
rproc_shutdown() rejects a remoteproc in RPROC_CRASHED state, and rproc_del() ignores that error. The result of these two decisions is that a user cannot stop a remoteproc that with recovery disabled that has entered a crash state, and removal of an associated remoteproc driver will release resources without first stopping the remoteproc.
Allow rproc_shutdown() to stop crashed processors. Propagate the crash state to subdevice teardown, to allow subdevices to dismantle things appropriately.
--- drivers/remoteproc/remoteproc_core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/remoteproc/remoteproc_core.c +5 -2
@@ -1989,6 +1989,7 @@ EXPORT_SYMBOL(rproc_boot);int rproc_shutdown (struct rproc *rproc) {struct device *dev = &rproc->dev; +bool crashed;int ret; ret =mutex_lock_interruptible (&rproc->lock);
@@ -1998,16 +1999,18 @@ int rproc_shutdown(struct rproc *rproc) }if (rproc->state !=RPROC_RUNNING && - rproc->state !=RPROC_ATTACHED ) { + rproc->state !=RPROC_ATTACHED && + rproc->state !=RPROC_CRASHED ) { ret = -EINVAL ; goto out; } + crashed = rproc->state ==RPROC_CRASHED ;/* if the remote proc is still needed, bail out */ if (!atomic_dec_and_test (&rproc->power)) goto out; - ret =rproc_stop (rproc, false); + ret =rproc_stop (rproc, crashed);if (ret) {atomic_inc (&rproc->power); goto out;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 704/1376 remoteproc: core: Attach rproc asynchronously in rproc_add() path via schedule_work()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jingyi Wang <[email protected]>
[ Upstream commit 026a3fada43261e403c6c4d9bda9501547e3f108 ]
Unlike the remoteproc firmware load path where rproc_add() call rproc_auto_boot_callback() asynchronously and ignores the return value of rproc_boot(), the attach path calls rproc_boot() synchronously and propagates its return value back to rproc_add(). This means a failure during rproc_attach() causes rproc_add() to fail and triggers resource release, removing the remoteproc from sysfs and making it unavailable for recovery or further boot attempts.
Align the remoteproc attach path with the firmware load path by introducing attach_work and scheduling rproc_boot() asynchronously via schedule_work(). This keeps the remoteproc registered and available in sysfs even if the initial attach attempt fails, and avoids blocking rproc_add() on the attach result.
Stable-dep-of: 74ee3b2f5767 ("remoteproc: Prevent crash handling to race with rproc_del()")
--- drivers/remoteproc/remoteproc_core.c | 20 ++++++++++++-------- include/linux/remoteproc.h | 2 ++ 2 files changed, 14 insertions(+), 8 deletions(-)
drivers/remoteproc/remoteproc_core.c +12 -8
@@ -1678,18 +1678,21 @@ static void rproc_auto_boot_callback(const struct firmware *fw, void *context)release_firmware (fw); } +static void rproc_attach_work (struct work_struct *work) +{ + struct rproc *rproc = container_of(work, struct rproc, attach_work); + +rproc_boot (rproc); +} +static int rproc_trigger_auto_boot (struct rproc *rproc) {int ret; -/* -* Since the remote processor is in a detached state, it has already -* been booted by another entity. As such there is no point in waiting -* for a firmware image to be loaded, we can simply initiate the process -* of attaching to it immediately. -*/ -if (rproc->state ==RPROC_DETACHED ) -return rproc_boot (rproc); +if (rproc->state ==RPROC_DETACHED ) { +schedule_work (&rproc->attach_work); +return 0 ; + }/* * We're initiating an asynchronous firmware loading, so we can
@@ -2521,6 +2524,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,INIT_LIST_HEAD (&rproc->dump_segments);INIT_WORK (&rproc->crash_handler, rproc_crash_handler_work); +INIT_WORK (&rproc->attach_work, rproc_attach_work); rproc->state =RPROC_OFFLINE ;
include/linux/remoteproc.h +2 -0
@@ -526,6 +526,7 @@ enum rproc_features {* @subdevs: list of subdevices, to following the running state * @notifyids: idr for dynamically assigning rproc-wide unique notify ids * @index: index of this rproc device +* @attach_work: workqueue for attaching rproc * @crash_handler: workqueue for handling a crash * @crash_cnt: crash counter * @recovery_disabled: flag that state if recovery was disabled
@@ -568,6 +569,7 @@ struct rproc {struct list_head subdevs;struct idr notifyids;int index; +struct work_struct attach_work;struct work_struct crash_handler;unsigned int crash_cnt;bool recovery_disabled;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 705/1376 remoteproc: Prevent crash handling to race with rproc_del()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bjorn Andersson <[email protected]>
[ Upstream commit 74ee3b2f5767447c57959994341e5b95f1079977 ]
There's no synchronization between rproc_crash_handler_work() and rproc_del(), as such it's possible for a driver to be removed while crash-handler work is scheduled, or even executing - resulting in use-after-free issues.
To avoid this the scheduled work need to be cancelled and synchronized against before the removal proceeds.
In order to ensure that this doesn't race with the reporting, and thereby scheduling new work, a "deleting" flag is introduced. This is similar to the RPROC_DELETE state that was introduced to ensure that "start" didn't race with rproc_del(), but the existing mechanism can not be used as it's valid to call rproc_report_crash() in atomic context - and the "state" is protected by a mutex.
In the event that work is cancelled the pm_stay_awake() is left unbalanced and need to be unrolled.
The blocking and cancelling of crash-handler work prior to the actual rproc_shutdown() call does have the explicit side-effect that crashes resulting from the shutdown process will not enter the crash-handling path, and as such will not generate devcoredumps etc. Due to the existing mutual exclusion between these code paths there's no concrete reduction in functionality, but further work would be needed to handle this case.
--- drivers/remoteproc/remoteproc_core.c | 42 +++++++++++++++++++++------ drivers/remoteproc/remoteproc_sysfs.c | 1 - include/linux/remoteproc.h | 13 +++++---- 3 files changed, 41 insertions(+), 15 deletions(-)
drivers/remoteproc/remoteproc_core.c +33 -9
@@ -1841,6 +1841,11 @@ int rproc_trigger_recovery(struct rproc *rproc)if (ret)return ret; +if (READ_ONCE (rproc->deleting)) { + ret = -ENODEV ; + goto unlock_mutex; + } +/* State could have changed before we got the mutex */ if (rproc->state !=RPROC_CRASHED ) goto unlock_mutex;
@@ -1873,6 +1878,11 @@ static void rproc_crash_handler_work(struct work_struct *work)mutex_lock (&rproc->lock); +if (READ_ONCE (rproc->deleting)) { +mutex_unlock (&rproc->lock); + goto out; + } +if (rproc->state ==RPROC_CRASHED ) {/* handle only the first crash detected */ mutex_unlock (&rproc->lock);
@@ -1928,9 +1938,9 @@ int rproc_boot(struct rproc *rproc)return ret; } -if (rproc->state ==RPROC_DELETED ) { +if (READ_ONCE (rproc->deleting)) { ret = -ENODEV ; -dev_err (dev,"can't boot deleted rproc %s\n" , rproc->name); +dev_err (dev,"can't boot deleting rproc %s\n" , rproc->name); goto unlock_mutex; }
@@ -2523,8 +2533,9 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,INIT_LIST_HEAD (&rproc->subdevs);INIT_LIST_HEAD (&rproc->dump_segments); -INIT_WORK (&rproc->crash_handler, rproc_crash_handler_work);INIT_WORK (&rproc->attach_work, rproc_attach_work); +INIT_WORK (&rproc->crash_handler, rproc_crash_handler_work); +spin_lock_init (&rproc->crash_handler_lock); rproc->state =RPROC_OFFLINE ;
@@ -2588,16 +2599,21 @@ EXPORT_SYMBOL(rproc_put);*/ int rproc_del (struct rproc *rproc) { +unsigned long flags; +if (!rproc)return -EINVAL ; +spin_lock_irqsave (&rproc->crash_handler_lock, flags); +WRITE_ONCE (rproc->deleting, true); +spin_unlock_irqrestore (&rproc->crash_handler_lock, flags); + +if (cancel_work_sync (&rproc->crash_handler)) +pm_relax (rproc->dev.parent); +/* TODO: make sure this works with rproc->power > 1 */ rproc_shutdown (rproc); -mutex_lock (&rproc->lock); - rproc->state =RPROC_DELETED ; -mutex_unlock (&rproc->lock); -rproc_delete_debug_dir (rproc);/* the rproc is downref'ed as soon as it's removed from the klist */
@@ -2709,18 +2725,26 @@ EXPORT_SYMBOL(rproc_get_by_child);*/ void rproc_report_crash (struct rproc *rproc,enum rproc_crash_type type) { +unsigned long flags; +if (!rproc) {pr_err ("NULL rproc pointer\n" );return ; } +spin_lock_irqsave (&rproc->crash_handler_lock, flags); +if (READ_ONCE (rproc->deleting)) { +spin_unlock_irqrestore (&rproc->crash_handler_lock, flags); +return ; + } +/* Prevent suspend while the remoteproc is being recovered */ pm_stay_awake (rproc->dev.parent); +queue_work (rproc_recovery_wq, &rproc->crash_handler); +spin_unlock_irqrestore (&rproc->crash_handler_lock, flags);dev_err (&rproc->dev,"crash detected in %s: type %s\n" , rproc->name,rproc_crash_to_string (type)); - -queue_work (rproc_recovery_wq, &rproc->crash_handler); }EXPORT_SYMBOL (rproc_report_crash);
drivers/remoteproc/remoteproc_sysfs.c +0 -1
@@ -168,7 +168,6 @@ static const char * const rproc_state_string[] = { [RPROC_SUSPENDED] = "suspended", [RPROC_RUNNING] = "running", [RPROC_CRASHED] = "crashed", - [RPROC_DELETED] = "deleted", [RPROC_ATTACHED] = "attached", [RPROC_DETACHED] = "detached", [RPROC_LAST] = "invalid",
include/linux/remoteproc.h +8 -5
@@ -37,6 +37,7 @@#include <linux/types.h> #include <linux/mutex.h> +#include <linux/spinlock.h> #include <linux/virtio.h> #include <linux/cdev.h> #include <linux/completion.h>
@@ -412,7 +413,6 @@ struct rproc_ops {* a message. * @RPROC_RUNNING: device is up and running * @RPROC_CRASHED: device has crashed; need to start recovery -* @RPROC_DELETED: device is deleted * @RPROC_ATTACHED: device has been booted by another entity and the core * has attached to it * @RPROC_DETACHED: device has been booted by another entity and waiting
@@ -430,10 +430,9 @@ enum rproc_state {RPROC_SUSPENDED =1 ,RPROC_RUNNING =2 ,RPROC_CRASHED =3 , -RPROC_DELETED =4 , -RPROC_ATTACHED =5 , -RPROC_DETACHED =6 , - RPROC_LAST = 7, +RPROC_ATTACHED =4 , +RPROC_DETACHED =5 , + RPROC_LAST = 6, };/**
@@ -528,6 +527,8 @@ enum rproc_features {* @index: index of this rproc device * @attach_work: workqueue for attaching rproc * @crash_handler: workqueue for handling a crash +* @crash_handler_lock: serializes crash handler queueing and deletion +* @deleting: remoteproc deletion has begun * @crash_cnt: crash counter * @recovery_disabled: flag that state if recovery was disabled * @max_notifyid: largest allocated notify id.
@@ -571,6 +572,8 @@ struct rproc {int index;struct work_struct attach_work;struct work_struct crash_handler; +spinlock_t crash_handler_lock; +bool deleting;unsigned int crash_cnt;bool recovery_disabled;int max_notifyid;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 706/1376 staging: rtl8723bs: use kfree_sensitive() for key material
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ivy Lopez <[email protected]>
[ Upstream commit d205dfa8cb825f1954ca1cfa474fc50bf06ee4aa ]
The set_stakey_parm struct contains a 16-byte encryption key. Use kfree_sensitive() instead of kfree() to ensure the key material is zeroed before the memory is freed, preventing potential information leaks.
--- drivers/staging/rtl8723bs/core/rtw_cmd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/staging/rtl8723bs/core/rtw_cmd.c +4 -4
@@ -894,7 +894,7 @@ u8 rtw_setstakey_cmd(struct adapter *padapter, struct sta_info *sta, u8 unicast_if (enqueue) { ph2c =rtw_zmalloc (sizeof (struct cmd_obj ));if (!ph2c) { -kfree (psetstakey_para); +kfree_sensitive (psetstakey_para); res = _FAIL; goto exit; }
@@ -902,7 +902,7 @@ u8 rtw_setstakey_cmd(struct adapter *padapter, struct sta_info *sta, u8 unicast_ psetstakey_rsp =rtw_zmalloc (sizeof (struct set_stakey_rsp ));if (!psetstakey_rsp) {kfree (ph2c); -kfree (psetstakey_para); +kfree_sensitive (psetstakey_para); res = _FAIL; goto exit; }
@@ -913,7 +913,7 @@ u8 rtw_setstakey_cmd(struct adapter *padapter, struct sta_info *sta, u8 unicast_ res =rtw_enqueue_cmd (pcmdpriv, ph2c); }else {set_stakey_hdl (padapter, (u8 *)psetstakey_para); -kfree (psetstakey_para); +kfree_sensitive (psetstakey_para); } exit:return res;
@@ -953,7 +953,7 @@ u8 rtw_clearstakey_cmd(struct adapter *padapter, struct sta_info *sta, u8 enqueu psetstakey_rsp =rtw_zmalloc (sizeof (struct set_stakey_rsp ));if (!psetstakey_rsp) {kfree (ph2c); -kfree (psetstakey_para); +kfree_sensitive (psetstakey_para); res = _FAIL; goto exit; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 707/1376 fs/ntfs3: reject restart table growth beyond U16_MAX entries
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit 111f8d74a19d85942ecbb3aba78f6f3c88e59391 ]
During $LogFile replay, log_replay() indexes the transaction table by the transact_id taken from the log record header. check_log_rec() only verifies that transact_id is non-zero and properly aligned, not its magnitude, so a crafted image can request an arbitrarily large index.
alloc_rsttbl_from_idx() grows the table to cover that index via extend_rsttbl(), which passes the new entry count to init_rsttbl():
rt = init_rsttbl(esize, used + add);
used + add is computed as u32 but init_rsttbl() takes a u16, and the count is stored in struct RESTART_TABLE as a __le16. When used + add exceeds U16_MAX it is truncated, init_rsttbl() allocates a table far smaller than the index requires, and alloc_rsttbl_from_idx() then dereferences and writes at the original, untruncated offset -- an out-of-bounds access past the allocation, reachable by mounting a crafted NTFS image.
BUG: KASAN: use-after-free in alloc_rsttbl_from_idx (fs/ntfs3/fslog.c:950) Read of size 4 at addr ffff8880327ffff8 by task exploit alloc_rsttbl_from_idx (fs/ntfs3/fslog.c:950) log_replay (fs/ntfs3/fslog.c:4562) ntfs_loadlog_and_replay (fs/ntfs3/fsntfs.c:324) ntfs_fill_super (fs/ntfs3/super.c:1393) get_tree_bdev_flags vfs_get_tree path_mount __x64_sys_mount
A restart table is limited to U16_MAX entries by its __le16 count, so a larger growth request is invalid input. Reject it in extend_rsttbl(); all callers already handle a NULL return.
--- fs/ntfs3/fslog.c | 3 +++ 1 file changed, 3 insertions(+)
fs/ntfs3/fslog.c +3 -0
@@ -875,6 +875,9 @@ static inline struct RESTART_TABLE *extend_rsttbl(struct RESTART_TABLE *tbl,u32 used =le16_to_cpu (tbl->used);struct RESTART_TABLE *rt; +if (used + add >U16_MAX ) +return NULL ; + rt =init_rsttbl (esize, used + add);if (!rt)return NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 708/1376 iommu/tegra241-cmdqv: Use request_threaded_irq
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolin Chen <[email protected]>
[ Upstream commit 1eb468744ccaafeaee145505d0aa5fd6227bd72f ]
A vEVENT can be reported only from a threaded IRQ context. Change to using request_threaded_irq to support that.
Stable-dep-of: 5acd67ceb38d ("iommu/tegra241-cmdqv: Don't run the error ISR before probe sets up vintfs")
--- drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c +3 -2
@@ -825,8 +825,9 @@ __tegra241_cmdqv_probe(struct arm_smmu_device *smmu, struct resource *res, cmdqv->dev = smmu->impl_dev;if (cmdqv->irq >0 ) { - ret =request_irq (irq, tegra241_cmdqv_isr,0 ,"tegra241-cmdqv" , - cmdqv); + ret =request_threaded_irq (irq,NULL , tegra241_cmdqv_isr, +IRQF_ONESHOT ,"tegra241-cmdqv" , + cmdqv);if (ret) {dev_err (cmdqv->dev,"failed to request irq (%d): %d\n" , cmdqv->irq, ret);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 709/1376 iommu/tegra241-cmdqv: Dont run the error ISR before probe sets up vintfs
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolin Chen <[email protected]>
[ Upstream commit 5acd67ceb38debe2fbf70ea35e2dec9f7ab01bbd ]
__tegra241_cmdqv_probe() requests the error IRQ before it has allocated the cmdqv->vintfs array and set cmdqv->num_vintfs. A CMDQV left enabled with a latched error across a kexec fires the IRQ as soon as it is requested, and tegra241_cmdqv_isr() then walks the uninitialized cmdqv->vintfs array.
Request the IRQ only after cmdqv->vintfs is allocated and zeroed, so that a latched interrupt firing early runs the ISR against a valid array of NULL slots that it safely skips.
--- .../iommu/arm/arm-smmu-v3/tegra241-cmdqv.c | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-)
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c +19 -15
@@ -824,17 +824,6 @@ __tegra241_cmdqv_probe(struct arm_smmu_device *smmu, struct resource *res, cmdqv->base = base; cmdqv->dev = smmu->impl_dev; -if (cmdqv->irq >0 ) { - ret =request_threaded_irq (irq,NULL , tegra241_cmdqv_isr, -IRQF_ONESHOT ,"tegra241-cmdqv" , - cmdqv); -if (ret) { -dev_err (cmdqv->dev,"failed to request irq (%d): %d\n" , - cmdqv->irq, ret); - goto iounmap; - } - } - regval =readl_relaxed (REG_CMDQV (cmdqv,PARAM )); cmdqv->num_vintfs =1 <<FIELD_GET (CMDQV_NUM_VINTF_LOG2 , regval); cmdqv->num_vcmdqs =1 <<FIELD_GET (CMDQV_NUM_VCMDQ_LOG2 , regval);
@@ -843,10 +832,25 @@ __tegra241_cmdqv_probe(struct arm_smmu_device *smmu, struct resource *res, cmdqv->vintfs =kcalloc (cmdqv->num_vintfs,sizeof (*cmdqv->vintfs),GFP_KERNEL );if (!cmdqv->vintfs) - goto free_irq; + goto iounmap;ida_init (&cmdqv->vintf_ids); +/* +* Request the IRQ only after cmdqv->vintfs is allocated and zeroed, so +* the ISR would not walk an uninitialized array. +*/ +if (cmdqv->irq >0 ) { + ret =request_threaded_irq (irq,NULL , tegra241_cmdqv_isr, +IRQF_ONESHOT ,"tegra241-cmdqv" , + cmdqv); +if (ret) { +dev_err (cmdqv->dev,"failed to request irq (%d): %d\n" , + cmdqv->irq, ret); + goto free_vintfs; + } + } +#ifdef CONFIG_IOMMU_DEBUGFS if (!cmdqv_debugfs_dir) { cmdqv_debugfs_dir =
@@ -861,9 +865,9 @@ __tegra241_cmdqv_probe(struct arm_smmu_device *smmu, struct resource *res,return new_smmu; -free_irq: -if (cmdqv->irq >0 ) -free_irq (cmdqv->irq, cmdqv); +free_vintfs: +ida_destroy (&cmdqv->vintf_ids); +kfree (cmdqv->vintfs); iounmap:iounmap (base);return NULL ;
Signature · 1 line
2.53.0
Re: [PATCH 6.12 0709/1376] iommu/tegra241-cmdqv: Dont run the error ISR before probe sets up vintfs
Quoted 62 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolin Chen <[email protected]>
[ Upstream commit
5acd67ceb38debe2fbf70ea35e2dec9f7ab01bbd]
__tegra241_cmdqv_probe()requests the error IRQ before it has allocated thecmdqv->vintfsarray and setcmdqv->num_vintfs. A CMDQV left enabled with a latched error across a kexec fires the IRQ as soon as it is requested, andtegra241_cmdqv_isr()then walks the uninitializedcmdqv->vintfsarray.Request the IRQ only after
cmdqv->vintfsis allocated and zeroed, so that a latched interrupt firing early runs the ISR against a valid array of NULL slots that it safely skips.Fixes 918eb5c856f6 ("iommu/arm-smmu-v3: Add in-kernel support for NVIDIA Tegra241 (Grace) CMDQV")Assisted-by Claude:claude-opus-4-8Signed-off-by Nicolin Chen <[email protected]>Signed-off-by Will Deacon <[email protected]>Signed-off-by Sasha Levin <[email protected]>--- .../iommu/arm/arm-smmu-v3/tegra241-cmdqv.c | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-)drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c +6
-12@@ -824,17 +824,6 @@ __tegra241_cmdqv_probe(struct arm_smmu_device *smmu, struct resource *res, cmdqv->base = base; cmdqv->dev = smmu->impl_dev; -if (cmdqv->irq >0 ) { - ret =request_threaded_irq (irq,NULL , tegra241_cmdqv_isr, -IRQF_ONESHOT ,"tegra241-cmdqv" , - cmdqv); -if (ret) { -dev_err (cmdqv->dev,"failed to request irq (%d): %d\n" , - cmdqv->irq, ret); - goto iounmap; - } - } - regval =readl_relaxed (REG_CMDQV (cmdqv,PARAM )); cmdqv->num_vintfs =1 <<FIELD_GET (CMDQV_NUM_VINTF_LOG2 , regval); cmdqv->num_vcmdqs =1 <<FIELD_GET (CMDQV_NUM_VCMDQ_LOG2 , regval);@@ -843,10 +832,25 @@ __tegra241_cmdqv_probe(struct arm_smmu_device *smmu, struct resource *res, cmdqv->vintfs =kcalloc (cmdqv->num_vintfs,sizeof (*cmdqv->vintfs),GFP_KERNEL );if (!cmdqv->vintfs) - goto free_irq; + goto iounmap;ida_init (&cmdqv->vintf_ids); +/* +* Request the IRQ only after cmdqv->vintfs is allocated and zeroed, so +* the ISR would not walk an uninitialized array. +*/ +if (cmdqv->irq >0 ) {
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c __tegra241_cmdqv_probe(struct arm_smmu_device *smmu, struct resource *res, · line 853
Quoted 10 lines
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c +10
-0+ ret =request_threaded_irq (irq,NULL , tegra241_cmdqv_isr, +IRQF_ONESHOT ,"tegra241-cmdqv" , + cmdqv); +if (ret) { +dev_err (cmdqv->dev,"failed to request irq (%d): %d\n" , + cmdqv->irq, ret); + goto free_vintfs; + } + } +
Hi Greg/Sasha,
I ran an AI-assisted backport review, and I have verified the report. It looks valid to me.
The patch allocates a zeroed vintfs array before registering the IRQ, but VINTF0 is created only later. A pending bit-zero error therefore calls the destination handler with vintfs[0] still NULL, and the handler dereferences it immediately.
Upstream safely skips that state only after the acquired NULL-safe ISR load and publication changes in cbc41aacd49e and a491be376abd.
Upstream code after a491be376abd:
vintf0 = smp_load_acquire(&cmdqv->vintfs[0]);
if (vintf0)
tegra241_vintf0_handle_error(vintf0);Downstream 6.12.y code:
if (vintf_map & BIT_ULL(0))
tegra241_vintf0_handle_error(cmdqv->vintfs[0]);The downstream ISR has neither an acquired load nor a NULL check.
This is a multi-commit initialization and lifetime model, not a safe reorder alone. Maybe we should be reverting or queueing more commits. Thoughts?
thanks,
Harshit
Quoted 16 lines
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c +3
-3#ifdef CONFIG_IOMMU_DEBUGFS if (!cmdqv_debugfs_dir) { cmdqv_debugfs_dir =@@ -861,9 +865,9 @@ __tegra241_cmdqv_probe(struct arm_smmu_device *smmu, struct resource *res,return new_smmu; -free_irq: -if (cmdqv->irq >0 ) -free_irq (cmdqv->irq, cmdqv); +free_vintfs: +ida_destroy (&cmdqv->vintf_ids); +kfree (cmdqv->vintfs); iounmap:iounmap (base);return NULL ;
Sasha Levin
maintainerRe: [PATCH 6.12 0709/1376] iommu/tegra241-cmdqv: Dont run the error ISR before probe sets up vintfs
Quoted 3 lines
This is a multi-commit initialization and lifetime model, not a safe reorder alone. Maybe we should be reverting or queueing more commits. Thoughts?
Queued cbc41aacd49e ("iommu/tegra241-cmdqv: Publish an LVCMDQ only after it is fully initialized") for 6.12.
a491be376abd ("iommu/tegra241-cmdqv: Synchronize the error ISR against VINTF (de)init") does not land there. Its Fixes: target is v6.17-rc1 and 6.12 has no iommufd viommu infrastructure, so the hunk carrying the memory safety payload rejects outright.
That leaves 6.12 with the narrow probe window you describe: the threaded IRQ is still requested before vintfs[0] is published. Closing it properly needs a purpose built 6.12 patch rather than a backport, so I am leaving it open for now.
Signature · 2 lines
Thanks, Sasha
Greg Kroah-Hartman
maintainerPATCH 710/1376 iommu/tegra241-cmdqv: Free the error IRQ before tearing down VINTFs
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolin Chen <[email protected]>
[ Upstream commit 61f0d437988e5730b04442f6a7d30a9907339f2a ]
tegra241_cmdqv_remove() tears each VINTF down first, then calls free_irq(). Tearing a VINTF down frees vintf0 and clears cmdqv->vintfs[0]. An error in that window makes tegra241_cmdqv_isr() read the stale slot and hand it to tegra241_vintf0_handle_error(), which dereferences a NULL or freed pointer.
Free the IRQ before tearing the VINTFs down. free_irq() waits for in-flight handlers to finish and blocks new ones, so no ISR can observe a VINTF as it is torn down.
Note: a user-owned VINTF (viommu) could outlive this teardown, which unmaps cmdqv->base and frees cmdqv->vintfs, so a later viommu close then touches freed memory. This is neither introduced nor fixed here: a physical IOMMU is not a pluggable device, so iommufd by design holds no reference on the one behind a viommu, and this teardown is not expected while that viommu is still alive.
--- drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c +8 -2
@@ -659,6 +659,14 @@ static void tegra241_cmdqv_remove(struct arm_smmu_device *smmu) container_of(smmu, struct tegra241_cmdqv, smmu);u16 idx; +/* +* Free the IRQ before tearing down the VINTFs. free_irq() waits for any +* in-flight tegra241_cmdqv_isr() to finish and blocks new ones, so the +* ISR cannot dereference a VINTF that is freed by the loop below. +*/ +if (cmdqv->irq >0 ) +free_irq (cmdqv->irq, cmdqv); +/* Remove VINTF resources */ for (idx =0 ; idx < cmdqv->num_vintfs; idx++) {if (cmdqv->vintfs[idx]) {
@@ -671,8 +679,6 @@ static void tegra241_cmdqv_remove(struct arm_smmu_device *smmu)/* Remove cmdqv resources */ ida_destroy (&cmdqv->vintf_ids); -if (cmdqv->irq >0 ) -free_irq (cmdqv->irq, cmdqv);iounmap (cmdqv->base);kfree (cmdqv->vintfs);put_device (cmdqv->dev);/* smmu->impl_dev */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 711/1376 RDMA/efa: Fix PBL chunk length computation
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yonatan Nachum <[email protected]>
[ Upstream commit 229b42d7450c1cf96f45ec39ebb69211b06bc036 ]
On register MR, when creating the PBL, if it's an indirect PBL we create a chunk list to hold the PBL pages pointers. Each chunk is 4KB in size and can hold 510 addresses (EFA_PTRS_PER_CHUNK) and has a 12-byte control buffer at the end of it holding the next chunk's pointer and its length.
If the PBL number of pages is a multiple of EFA_PTRS_PER_CHUNK, the calculated last chunk length is wrongly computed as 0, even though that chunk is fully populated with 510 real page pointers. This wrong length is used both to DMA map the chunk and is propagated to the device, causing the device to see the chunk as empty and reject the memory registration.
Fix the calculation so it will be performed only if the number of pages isn't a multiple of EFA_PTRS_PER_CHUNK, if it is, its already handled in the above loop correctly.
Also prevent out-of-bounds reach in the chunks array in such scenario.
--- drivers/infiniband/hw/efa/efa_verbs.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
drivers/infiniband/hw/efa/efa_verbs.c +9 -4
@@ -1313,9 +1313,11 @@ static int pbl_chunk_list_create(struct efa_dev *dev, struct pbl_context *pbl) chunk_list->chunks[i].length =EFA_CHUNK_USED_SIZE ; } - chunk_list->chunks[chunk_list_size -1 ].length = - ((page_cnt %EFA_PTRS_PER_CHUNK ) *EFA_CHUNK_PAYLOAD_PTR_SIZE ) + -EFA_CHUNK_PTR_SIZE ; + +if (page_cnt %EFA_PTRS_PER_CHUNK !=0 ) + chunk_list->chunks[chunk_list_size -1 ].length = + ((page_cnt %EFA_PTRS_PER_CHUNK ) *EFA_CHUNK_PAYLOAD_PTR_SIZE ) + +EFA_CHUNK_PTR_SIZE ;/* fill the dma addresses of sg list pages to chunks: */ chunk_idx =0 ;
@@ -1327,9 +1329,12 @@ static int pbl_chunk_list_create(struct efa_dev *dev, struct pbl_context *pbl)rdma_block_iter_dma_address (&biter);if (payload_idx ==EFA_PTRS_PER_CHUNK ) { + payload_idx =0 ; chunk_idx++; +if (chunk_idx >= chunk_list_size) +break ; + cur_chunk_buf = chunk_list->chunks[chunk_idx].buf; - payload_idx =0 ; } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 712/1376 wifi: mac80211: fix per-STA profile length in cross-link CSA parsing
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhao Li <[email protected]>
[ Upstream commit 4a0bd262df757b25fc4e2a53c947317c119ced4e ]
ieee80211_mgd_check_cross_link_csa() starts parsing elements after the fixed per-STA profile header and the STA Info field, but subtracts only the STA Info length from the profile length. As a result, ieee802_11_parse_elems() is given sizeof(*prof) == 3 bytes beyond the current profile's element area, and data following the profile may be interpreted as belonging to it.
Subtract the fixed profile header as well. The preceding ieee80211_mle_basic_sta_prof_size_ok() check guarantees that the corrected calculation cannot underflow, and ieee80211_rx_uhr_link_reconfig_req() uses the same calculation.
The call site currently states that cross-link CSA parsing has no effect because the broader parsing is still incorrect. This patch does not address that broader problem; it only makes the per-STA profile parser stop at the end of that profile. No production allocation over-read or user-visible failure has been demonstrated.
--- net/mac80211/mlme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/mac80211/mlme.c +1 -1
@@ -6660,7 +6660,7 @@ ieee80211_mgd_check_cross_link_csa(struct ieee80211_sub_if_data *sdata, prof = (void *)sta_profiles[link_id]; prof_elems =ieee802_11_parse_elems (prof->variable + (prof->sta_info_len -1 ), - len - + len -sizeof (*prof) - (prof->sta_info_len -1 ), false,NULL );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 713/1376 arm64: dts: allwinner: sun50i-a64-pinephone: Fix mpu6050 mount matrix
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ondrej Jirman <[email protected]>
[ Upstream commit dfc735fd93e4814e65894916ec5f807f25a391d1 ]
The current mount matrix for mpu6050 is wrong. The mount matrix is a simple transform from the sensor coordinate space to the device coordinate space described in DT, where, looking at the screen, X points to the right, Y to the top, and Z towards the user.
The mpu6050 is mounted like this (looking at the screen from the front; the sensor is on the near side of the PCB, so its Z axis points towards the user; o marks the pin 1 corner):
+Xs
^
|
+------+
+Ys <--| |
| o |
+------+so this gives:
Xd = -Ys [0, -1, 0] Yd = Xs [1, 0, 0] Zd = Zs [0, 0, 1]
--- arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi +2 -2
@@ -212,8 +212,8 @@ accelerometer@68 { interrupts = <7 5 IRQ_TYPE_EDGE_RISING>; /* PH5 */ vdd-supply = <®_dldo1>; vddio-supply = <®_dldo1>; - mount-matrix = "0", "1", "0", - "-1", "0", "0", + mount-matrix = "0", "-1", "0", + "1", "0", "0", "0", "0", "1"; }; };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 714/1376 clk: tegra: tegra124-emc: put EMC node on register failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
[ Upstream commit f726279f5eab813f9a8b6f38ddf2a4b062d038ff ]
tegra124_clk_register_emc() stores a device node reference returned by of_parse_phandle() in tegra->emc_node.
If clk_register() fails, the function returns an error before that reference can be consumed and released by the normal runtime path. The tegra_clk_emc object is freed on this failure path, but freeing the object does not drop the OF node reference stored in it.
Drop the EMC node reference before freeing the tegra_clk_emc object. of_node_put() is safe for a NULL node, so this also covers the case where the phandle is absent.
--- drivers/clk/tegra/clk-tegra124-emc.c | 1 + 1 file changed, 1 insertion(+)
drivers/clk/tegra/clk-tegra124-emc.c +1 -0
@@ -539,6 +539,7 @@ struct clk *tegra124_clk_register_emc(void __iomem *base, struct device_node *np clk =clk_register (NULL , &tegra->hw);if (IS_ERR (clk)) { +of_node_put (tegra->emc_node);kfree (tegra);return clk; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 715/1376 clk: palmas: Manage external-control prepare with devm
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
[ Upstream commit ccda84fcbf3a972973f772384935928f41817b3a ]
palmas_clks_init_configure() prepares the clock when an external control pin is configured. The current driver only drops that prepare reference when external control configuration fails.
If provider registration fails after that point, or if the driver is later removed, the prepare reference remains held.
Register a device-managed action after clk_prepare() succeeds. This balances the prepare reference on subsequent probe failure and driver removal.
--- drivers/clk/clk-palmas.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
drivers/clk/clk-palmas.c +13 -1
@@ -194,6 +194,13 @@ static void palmas_clks_get_clk_data(struct platform_device *pdev, cinfo->ext_control_pin = prop; } +static void palmas_clks_unprepare_ext_control (void *data) +{ +struct palmas_clock_info *cinfo = data; + +clk_unprepare (cinfo->hw.clk); +} +static int palmas_clks_init_configure (struct palmas_clock_info *cinfo) {int ret;
@@ -214,13 +221,18 @@ static int palmas_clks_init_configure(struct palmas_clock_info *cinfo)return ret; } + ret =devm_add_action_or_reset (cinfo->dev, + palmas_clks_unprepare_ext_control, + cinfo); +if (ret) +return ret; + ret =palmas_ext_control_req_config (cinfo->palmas, cinfo->clk_desc->sleep_reqstr_id, cinfo->ext_control_pin, true);if (ret <0 ) {dev_err (cinfo->dev,"Ext config for %s failed, %d\n" , cinfo->clk_desc->clk_name, ret); -clk_unprepare (cinfo->hw.clk);return ret; } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 716/1376 clk/x86: pmc_atom: add kasprintf return value check
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: longlong yan <[email protected]>
[ Upstream commit 18e9d14cbac33db1c1fb933c26a736eef53dd538 ]
The kasprintf() function returns NULL on memory allocation failure, but the code in plt_clk_register() was not checking this return value. If kasprintf fails, init.name would be NULL and could cause NULL pointer dereference when clkdev_hw_create() uses it.
Add proper error checking for the kasprintf() return value and return ERR_PTR(-ENOMEM) on failure.
--- drivers/clk/x86/clk-pmc-atom.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/clk/x86/clk-pmc-atom.c +3 -0
@@ -160,6 +160,9 @@ static struct clk_plt *plt_clk_register(struct platform_device *pdev, int id,return ERR_PTR (-ENOMEM ); init.name =kasprintf (GFP_KERNEL ,"%s_%d" ,PLT_CLK_NAME_BASE , id); +if (!init.name) +return ERR_PTR (-ENOMEM ); + init.ops = &plt_clk_ops; init.flags =0 ; init.parent_names = parent_names;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 717/1376 clk: mediatek: mt8135: Fix inverted gate control for devapc_ck
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Akari Tsuyukusa <[email protected]>
[ Upstream commit fd0e3e4edea6a3e4da91be608ca2fb9b348f9e32 ]
The devapc_ck (CLK_INFRA_DEVAPC) on MT8135 is currently using "mtk_clk_gate_ops_setclr". However, checking the downstream kernel reveals that this clock is configured with set:enable and clr:disable making "mtk_clk_gate_ops_setclr_inv" the appropriate choice.
But, it is strange that some downstream kernels are not like that.
Amazon: INV
ChromiumOS (early): not INV
ChromiumOS 3.16 to 3.18-revew-v2: INV
ChromiumOS 3.18-review-v3 and later (sent to kernel.org): not INV
--- drivers/clk/mediatek/clk-mt8135.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/clk/mediatek/clk-mt8135.c +4 -1
@@ -409,6 +409,9 @@ static const struct mtk_gate_regs infra_cg_regs = {GATE_MTK_FLAGS (_id, _name, _parent, &infra_cg_regs, _shift, \ &mtk_clk_gate_ops_setclr, CLK_IS_CRITICAL) +#define GATE_ICG_INV (_id, _name, _parent, _shift) \ + GATE_MTK(_id, _name, _parent, &infra_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv) +static const struct mtk_gate infra_clks[] = {GATE_DUMMY (CLK_DUMMY ,"infra_dummy" ),GATE_ICG (CLK_INFRA_PMIC_WRAP ,"pmic_wrap_ck" ,"axi_sel" ,23 ),
@@ -419,7 +422,7 @@ static const struct mtk_gate infra_clks[] = {GATE_ICG (CLK_INFRA_CPUM ,"cpum_ck" ,"cpum_tck_in" ,15 ),GATE_ICG_AO (CLK_INFRA_M4U ,"m4u_ck" ,"mem_sel" ,8 ),GATE_ICG (CLK_INFRA_MFGAXI ,"mfgaxi_ck" ,"axi_sel" ,7 ), -GATE_ICG (CLK_INFRA_DEVAPC ,"devapc_ck" ,"axi_sel" ,6 ), +GATE_ICG_INV (CLK_INFRA_DEVAPC ,"devapc_ck" ,"axi_sel" ,6 ),GATE_ICG (CLK_INFRA_AUDIO ,"audio_ck" ,"aud_intbus_sel" ,5 ),GATE_ICG (CLK_INFRA_MFG_BUS ,"mfg_bus_ck" ,"axi_sel" ,2 ), GATE_ICG(CLK_INFRA_SMI, "smi_ck", "smi_sel", 1),
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 718/1376 clk: rockchip: Fix the fractional part denominator on RK3588/RK3576 PLLs
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexey Charkov <[email protected]>
[ Upstream commit 52aef653c3d0c24013dfa9eccf692594eacdbe17 ]
According to the TRM, the fractional PLL coefficient should be divided by 65536 rather than 65535 to obtain the output rate.
Fix the denominator and add a comment with the TRM provided clock formulae for future reference.
See RK3576 TRM Part 1 V1.2 section 2.13.1.4 Setting Guide on P, M, S and K or equivalently RK3588 TRM part 1 V1.0 section 2.17.1.4 Setting Guide on P, M, S and K.
Fractional PLL rates don't seem to be used by any current mainline consumers, so this is purely a correctness fix. It will also be important to properly support DisplayPort output going forward, as the video output controller derives its pixel clock from system PLLs with no dedicated PHY PLL option for DP unlike HDMI, and some display modes are only achievable with fractional PLL rates.
--- drivers/clk/rockchip/clk-pll.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/clk/rockchip/clk-pll.c +8 -1
@@ -893,6 +893,13 @@ static void rockchip_rk3588_pll_get_params(struct rockchip_clk_pll *pll, rate->k = ((pllcon >>RK3588_PLLCON2_K_SHIFT ) &RK3588_PLLCON2_K_MASK ); } +/* +* 2250 MHz <= Fvco <= 4500 MHz +* For Fvco > 3 GHz: period jitter +-1% frac PLL, +-0.75% int PLL +* For Fvco < 3 GHz: period jitter +-2% frac PLL, +-1.50% int PLL +* Fvco = ((m + k / 65536) * Fin) / p +* Fout = ((m + k / 65536) * Fin) / (p * 2^s) +*/ static unsigned long rockchip_rk3588_pll_recalc_rate (struct clk_hw *hw,unsigned long prate) {struct rockchip_clk_pll *pll =to_rockchip_clk_pll (hw);
@@ -908,7 +915,7 @@ static unsigned long rockchip_rk3588_pll_recalc_rate(struct clk_hw *hw, unsigned/* fractional mode */ u64 frac_rate64 = prate * cur.k; - postdiv = cur.p *65535 ; + postdiv = cur.p *65536 ;do_div (frac_rate64, postdiv); rate64 += frac_rate64; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 719/1376 nilfs2: fix infinite loop in nilfs_clean_segments()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joshua Crofts <[email protected]>
[ Upstream commit ce5a5ad1a8330a2fcfdd9ec2ab341be739e89a18 ]
syzbot reported a hung task in nilfs_transaction_begin(). This occurs because the cleaner ioctl falls into an infinite loop if nilfs_segctor_construct() repeatedly returns -EROFS (e.g. the device is remounted as read-only after an I/O error).
Currently in nilfs_clean_segments(), if err is non-zero, it logs the error and sleeps but doesn't abort when it encounters a terminal error like -EROFS. This causes the thread to loop forever.
Fix this by breaking out of the loop if nilfs_segctor_construct() returns -EROFS. This matches the behaviour in nilfs_segctor_write_out(), which also handles -EROFS.
--- fs/nilfs2/segment.c | 4 ++++ 1 file changed, 4 insertions(+)
fs/nilfs2/segment.c +4 -0
@@ -2580,6 +2580,10 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv,break ;nilfs_warn (sb,"error %d cleaning segments" , err); + +if (unlikely (err == -EROFS )) + goto out_unlock; +set_current_state (TASK_INTERRUPTIBLE );schedule_timeout (sci->sc_interval); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 720/1376 nilfs2: prevent out-of-bounds read in super root block parsing
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Lee <[email protected]>
[ Upstream commit 7cb2f76a6a2ba2130b577cb8ac13e1e46c4fc689 ]
super-root inode metadata size is trusted before nilfs_read_inode_common().
Reject super-root inode sizes whose computed on-disk footprint exceeds the filesystem block size. This prevents malformed filesystem images from making nilfs_read_inode_common() read past the end of the super-root block.
[ryusuke: clarify the commit title]
--- fs/nilfs2/the_nilfs.c | 6 ++++++ 1 file changed, 6 insertions(+)
fs/nilfs2/the_nilfs.c +6 -0
@@ -448,6 +448,12 @@ static int nilfs_store_disk_layout(struct the_nilfs *nilfs, nilfs->ns_inode_size);return -EINVAL ; } +if (NILFS_SR_BYTES (nilfs->ns_inode_size) > nilfs->ns_blocksize) { +nilfs_err (nilfs->ns_sb, +"too large inode size for super root: %d bytes" , + nilfs->ns_inode_size); +return -EINVAL ; + } nilfs->ns_first_ino =le32_to_cpu (sbp->s_first_ino);if (nilfs->ns_first_ino <NILFS_USER_INO ) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 721/1376 nilfs2: fix BUG in nilfs_copy_dirty_pages() on dirty state mismatch
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ryusuke Konishi <[email protected]>
[ Upstream commit 66f4ad3ce158902e5f98afea93189972ed8750c2 ]
Syzbot reported a kernel BUG triggered within nilfs_copy_dirty_pages(), which copies dirty DAT file folios/pages to its shadow page cache. The BUG occurs when a retrieved dirty folio/page unexpectedly loses its 'dirty' status.
This issue arises because, since the commit referenced below, the 'dirty' flag of a folio/page can be cleared asynchronously after the filesystem detects metadata corruption and transitions to read-only mode.
Resolve the issue by returning an -EROFS error if the filesystem has transitioned to read-only mode. Also change the behavior to issue a kernel warning only once instead of triggering a kernel BUG when this unexpected 'dirty' state is detected while the filesystem is not in read-only mode.
--- fs/nilfs2/page.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)
fs/nilfs2/page.c +15 -2
@@ -244,6 +244,7 @@ static void nilfs_copy_folio(struct folio *dst, struct folio *src,int nilfs_copy_dirty_pages (struct address_space *dmap,struct address_space *smap) { +struct inode *smap_inode = smap->host;struct folio_batch fbatch;unsigned int i;pgoff_t index =0 ;
@@ -259,8 +260,19 @@ int nilfs_copy_dirty_pages(struct address_space *dmap,struct folio *folio = fbatch.folios[i], *dfolio;folio_lock (folio); -if (unlikely (!folio_test_dirty (folio))) -NILFS_FOLIO_BUG (folio,"inconsistent dirty state" ); +if (unlikely (!folio_test_dirty (folio))) { +if (WARN_ONCE (!sb_rdonly (smap_inode->i_sb), +"inconsistent dirty state\n" )) + goto unlock_folio; + +/* +* If the filesystem has been forced to read-only +* due to metadata corruption. +*/ +folio_unlock (folio); + err = -EROFS ; +break ; + } dfolio =filemap_grab_folio (dmap, folio->index);if (IS_ERR (dfolio)) {
@@ -278,6 +290,7 @@ int nilfs_copy_dirty_pages(struct address_space *dmap,folio_unlock (dfolio);folio_put (dfolio); +unlock_folio:folio_unlock (folio); }folio_batch_release (&fbatch);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 722/1376 scsi: smartpqi: Fix AIO retry marker cleared by SCSI core between dispatches.
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Strahan <[email protected]>
[ Upstream commit 225548863f0a2350c6f34231ca56710c3dd1a5d5 ]
On recent Linux kernels the driver can enter a retry loop on the AIO fast path when a request is retried, looping until timeout. A diagnostic path that takes a physical drive offline on AIO-bypass failure is also never entered on affected kernels.
Register a per-command initialization callback with the SCSI core. Its presence causes the core to skip the per-dispatch clear, so the retry marker now survives across the requeue and the AIO-to-RAID fallback proceeds as intended. The driver takes over the marker's lifetime: it is zeroed at tag allocation, preserved across the retry requeue so the error path can act on it, and cleared on terminal completion so the tag starts clean on its next use.
--- drivers/scsi/smartpqi/smartpqi_init.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
drivers/scsi/smartpqi/smartpqi_init.c +18 -0
@@ -65,6 +65,12 @@ static struct pqi_cmd_priv *pqi_cmd_priv(struct scsi_cmnd *cmd)return scsi_cmd_priv (cmd); } +static int pqi_init_cmd_priv (struct Scsi_Host *shost,struct scsi_cmnd *cmd) +{ +memset (pqi_cmd_priv (cmd),0 ,sizeof (struct pqi_cmd_priv )); +return 0 ; +} +static void pqi_verify_structures (void );static void pqi_take_ctrl_offline (struct pqi_ctrl_info *ctrl_info,enum pqi_ctrl_shutdown_reason ctrl_shutdown_reason);
@@ -5928,6 +5934,17 @@ void pqi_prep_for_scsi_done(struct scsi_cmnd *scmd)struct pqi_scsi_dev *device;struct completion *wait; +/* +* Clear the AIO-retry marker on final completion so the tag +* starts clean on its next dispatch. On DID_IMM_RETRY leave +* it intact: pqi_aio_io_complete() sets DID_IMM_RETRY and +* bumps the marker to steer the requeue onto the RAID path, +* and pqi_process_raid_io_error() consumes the non-zero +* marker to offline a misbehaving drive. +*/ +if (host_byte (scmd->result) !=DID_IMM_RETRY ) +pqi_cmd_priv (scmd)->this_residual =0 ; +if (!scmd->device) {set_host_byte (scmd,DID_NO_CONNECT );return ;
@@ -7582,6 +7599,7 @@ static const struct scsi_host_template pqi_driver_template = { .sdev_groups = pqi_sdev_groups, .shost_groups = pqi_shost_groups, .cmd_size = sizeof(struct pqi_cmd_priv), + .init_cmd_priv = pqi_init_cmd_priv, };static int pqi_register_scsi (struct pqi_ctrl_info *ctrl_info)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 723/1376 RDMA/mlx5: Fix stack out-of-bounds read in cc_params debugfs
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Romanovsky <[email protected]>
[ Upstream commit 03826bc1fa6c90405bf05831f2b501a8368dcd27 ]
get_param() reads a congestion parameter as a u32 but formats it with the signed "%d" into an 11-byte stack buffer. A value with bit 31 set, such as 0x80000000, renders as "-2147483648\n" whose full length is 12. snprintf() stores only 11 bytes yet returns 12, so simple_read_from_buffer() treats 12 bytes as valid and reads one byte past lbuf[].
Size the buffer for the widest unsigned decimal, format with "%u" to match the u32, and use scnprintf() so the length passed to simple_read_from_buffer() reflects the bytes actually stored.
--- drivers/infiniband/hw/mlx5/cong.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/infiniband/hw/mlx5/cong.c +2 -4
@@ -399,15 +399,13 @@ static ssize_t get_param(struct file *filp, char __user *buf, size_t count,int offset = param->offset;u32 var =0 ;int ret; -char lbuf[11 ]; +char lbuf[12 ]; ret =mlx5_ib_get_cc_params (param->dev, param->port_num, offset, &var);if (ret)return ret; - ret =snprintf (lbuf,sizeof (lbuf),"%d\n" , var); -if (ret <0 ) -return ret; + ret =scnprintf (lbuf,sizeof (lbuf),"%u\n" , var);return simple_read_from_buffer (buf, count, pos, lbuf, ret); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 724/1376 RDMA/mlx5: Send cong param changes to the resolved port mdev
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Romanovsky <[email protected]>
[ Upstream commit 033a79e308e4fe832b0924347eda8c4364055174 ]
mlx5_ib_set_cc_params() resolves the port-specific mlx5_core_dev via mlx5_ib_get_native_port_mdev() but issued MLX5_CMD_OP_MODIFY_CONG_PARAMS through dev->mdev. On an affiliated secondary RoCE port those pointers refer to different devices, so a write to the secondary port's cc_params debugfs file either altered the master port or failed with a master-side command error, while the read path already used the resolved mdev and returned the unchanged secondary value.
Issue the command to the resolved mdev, the same device whose capabilities were checked when its debugfs directory was created. It is already referenced by the get/put pair, so its lifetime is safe.
--- drivers/infiniband/hw/mlx5/cong.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/infiniband/hw/mlx5/cong.c +1 -1
@@ -361,7 +361,7 @@ static int mlx5_ib_set_cc_params(struct mlx5_ib_dev *dev, u32 port_num,MLX5_SET (field_select_r_roce_rp, field, field_select_r_roce_rp, attr_mask); - err =mlx5_cmd_exec_in (dev->mdev, modify_cong_params, in); + err =mlx5_cmd_exec_in (mdev, modify_cong_params, in);kvfree (in); alloc_err:mlx5_ib_put_native_port_mdev (dev, port_num +1 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 725/1376 RDMA/cxgb4: free STAG index when TPT entry write fails
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Romanovsky <[email protected]>
[ Upstream commit fdfb5cea4bf070cdb31d997efd87bb684df041fd ]
write_tpt_entry() allocates a new STAG index with c4iw_get_resource() and bumps stats.stag.cur before programming the entry. When write_adapter_mem() fails, it returns the error without releasing the index or reversing the statistic. No MR is inserted into rhp->mrs, so deregistration never reclaims it, leaking the index until device teardown.
Record whether this call allocated the index and, on a failed write, return it to tpt_table and decrement stats.stag.cur. Key the rollback on both the write error and that flag, not the error alone: a non-reset update carries a caller-owned STAG that this call did not allocate and must not free.
--- drivers/infiniband/hw/cxgb4/mem.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/infiniband/hw/cxgb4/mem.c +3 -1
@@ -277,6 +277,7 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry,int err;struct fw_ri_tpte *tpt;u32 stag_idx; +bool stag_idx_allocated = false;static atomic_t key;if (c4iw_fatal_error (rdev))
@@ -299,6 +300,7 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry,return -ENOMEM ; }mutex_lock (&rdev->stats.lock); + stag_idx_allocated = true; rdev->stats.stag.cur +=32 ;if (rdev->stats.stag.cur > rdev->stats.stag.max) rdev->stats.stag.max = rdev->stats.stag.cur;
@@ -333,7 +335,7 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry, (rdev->lldi.vr->stag.start >>5 ), sizeof(*tpt), tpt, skb, wr_waitp); -if (reset_tpt_entry) { +if (reset_tpt_entry || (err && stag_idx_allocated)) {c4iw_put_resource (&rdev->resource.tpt_table, stag_idx);mutex_lock (&rdev->stats.lock); rdev->stats.stag.cur -=32 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 726/1376 IB/isert: reject PDUs declaring more data than was received
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yehyeong Lee <[email protected]>
[ Upstream commit 957f92ea4022fb6af4618271615a2a21a7b5bef9 ]
isert_recv_done() hands each received PDU to the opcode handlers without ever looking at wc->byte_len, the number of bytes the HCA actually placed in the receive descriptor. The handlers then copy that many bytes - the data-segment length the initiator declared in the BHS (ntoh24(hdr->dlength), via the derived unsol_data_len / imm_data_len) - out of the fixed-size descriptor:
isert_handle_iscsi_dataout():
sg_copy_from_buffer(sg_start, sg_nents, isert_get_data(rx_desc),
unsol_data_len);
isert_handle_scsi_cmd():
sg_copy_from_buffer(cmd->se_cmd.t_data_sg, sg_nents,
isert_get_data(rx_desc), imm_data_len);Because the declared length is never checked against wc->byte_len, an initiator can declare a data segment larger than the bytes it actually sent (and larger than the descriptor) and cause an out-of-bounds read of the receive buffer.
Nothing upstream of isert closes this door:
- __iscsit_check_dataout_hdr() bounds the inbound payload against conn_ops->MaxXmitDataSegmentLength (MXDSL) - a transmit parameter, used here for the inbound check.
- iscsi_set_connection_parameters() sets ops->MaxXmitDataSegmentLength = ops->TargetRecvDataSegmentLength; and TARGETRECVDATASEGMENTLENGTH is absent from the min()-clamp list in iscsi_check_acceptor_state(), so the value the initiator declares is adopted verbatim (type range 512..16777215). The initiator effectively raises its own ceiling.
- isert never clamps the negotiated value to its own fixed receive descriptor (ISER_RX_SIZE, 9216 bytes), so the target core's bound and the descriptor size are unrelated.
The imm_data_len == data_len path is more than an over-read: it aliases the receive descriptor via sg_set_buf() and passes it to the backend as the data source for the SCSI WRITE, so an over-declared length causes heap contents past the descriptor to be written through the backend to the backing store. The backend is the victim of the oversized scatterlist isert hands it, not the cause; no read-back of the written bytes was demonstrated.
Trigger: after login completes (full feature phase), an initiator that has declared a large TargetRecvDataSegmentLength and a FirstBurstLength that permits unsolicited/immediate data sends a PDU whose declared data-segment length exceeds what was received. With KASAN:
BUG: KASAN: slab-out-of-bounds in sg_copy_buffer+0x150/0x1c0 Read of size 4096 at addr ffff888109720800 by task kworker/1:0H/25 Workqueue: ib-comp-wq ib_cq_poll_work Call Trace: sg_copy_buffer+0x150/0x1c0 isert_recv_done+0xba6/0x2390 __ib_process_cq+0xe1/0x390 ib_cq_poll_work+0x46/0x150
isert_recv_done+0xba6 resolves to isert_handle_iscsi_dataout() (ib_isert.c:1160), inlined through isert_rx_opcode().
Validate wc->byte_len against the framing in isert_recv_done() before the PDU reaches any handler, and reinstate the connection if it is short. Because the test compares without subtracting the header length, it also rejects PDUs shorter than the iSER and iSCSI headers, which would otherwise be parsed out of stale descriptor contents. The login handler rejects PDUs shorter than ISER_HEADERS_LEN (commit 29e7b925ae6d ("IB/isert: Reject login PDUs shorter than ISER_HEADERS_LEN")) but does not bound the declared length either; that is fixed in the next patch. The data handlers had no length check at all.
isert reads the data segment from a fixed offset: isert_get_data() returns the iSER header plus ISER_HEADERS_LEN and makes no adjustment for an AHS. The bytes the handlers touch are therefore exactly [ISER_HEADERS_LEN, ISER_HEADERS_LEN + dlength), and comparing that sum against wc->byte_len bounds precisely the region that is read. An AHS term would only make the test stricter without bounding anything further, and cannot cause a false reject: a PDU carrying an AHS is longer, not shorter.
This is a memory-safety fix that verifies the bytes that were actually received; it does not touch RFC 7145 length negotiation and is not the MaxXmitDataSegmentLength negotiation redesign raised in the 2017 "[Query]
iSER-Target: QP errors observed on increasing MaxXmitDataSegmentLength" discussion. That redesign is explicitly out of scope here.
The patched kernel rejects the malformed DataOut PDU and both immediate-data variants with "PDU declares ... bytes were received" and continues to pass normal traffic with no regression.
Reproduced with soft-RoCE (rdma_rxe) and a raw rdma_cm/ibv initiator; no kernel-side test hooks were needed.
--- drivers/infiniband/ulp/isert/ib_isert.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
drivers/infiniband/ulp/isert/ib_isert.c +15 -0
@@ -1335,6 +1335,21 @@ isert_recv_done(struct ib_cq *cq, struct ib_wc *wc)ib_dma_sync_single_for_cpu (ib_dev, rx_desc->dma_addr,ISER_RX_SIZE ,DMA_FROM_DEVICE ); +/* +* The data segment length declared in the BHS is attacker controlled +* and is used further down to read that many bytes out of the fixed +* size receive descriptor, so it has to be checked against the number +* of bytes that were actually received. Comparing without subtracting +* also rejects PDUs shorter than the iSER and iSCSI headers, which +* would otherwise be parsed out of stale descriptor contents. +*/ +if (unlikely (wc->byte_len <ISER_HEADERS_LEN +ntoh24 (hdr->dlength))) { +isert_err ("PDU declares %u data bytes but only %u bytes were received\n" , +ntoh24 (hdr->dlength), wc->byte_len); +iscsit_cause_connection_reinstatement (isert_conn->conn,0 ); +return ; + } +isert_dbg ("DMA: 0x%llx, iSCSI opcode: 0x%02x, ITT: 0x%08x, flags: 0x%02x dlen: %d\n" , rx_desc->dma_addr, hdr->opcode, hdr->itt, hdr->flags, (int )(wc->byte_len -ISER_HEADERS_LEN ));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 727/1376 IB/isert: reject login PDUs declaring more data than was received
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yehyeong Lee <[email protected]>
[ Upstream commit 2488b5b4827e5415768afc8daf097e8eb83c98df ]
isert_login_recv_done() records how many bytes the HCA actually placed in the login buffer, but nothing compares that against the length the login PDU's BHS declares. isert_rx_login_req() copies min(login_req_len, MAX_KEY_VALUE_PAIRS) bytes into login->req_buf, and the login code then reads the declared length back out of that buffer - for the first PDU in iscsi_target_locate_portal(),
payload_length = ntoh24(login_req->dlength); tmpbuf = kmemdup_nul(login->req_buf, payload_length, GFP_KERNEL);
and for the ones after it in iscsi_decode_text_input(), reached from iscsi_target_do_login().
login->req_buf is a fixed MAX_KEY_VALUE_PAIRS (8192) byte allocation, so an initiator that declares more than it sends reads off the end of it, before authentication and with the length under its control:
BUG: KASAN: slab-out-of-bounds in kmemdup_nul+0x43/0x80 Read of size 8193 at addr ffff8881056a8000 by task iscsi_np/167 __asan_memcpy+0x23/0x60 kmemdup_nul+0x43/0x80 iscsi_target_locate_portal+0x48d/0x1180 iscsi_target_login_thread+0x19a9/0x3350 Allocated by task 167: __kmalloc_cache_noprof+0x158/0x370 iscsi_target_login_thread+0x971/0x3350 which belongs to the cache kmalloc-8k of size 8192 allocated 8192-byte region
Falsifying the second login PDU instead reaches the other reader, on the same buffer:
BUG: KASAN: slab-out-of-bounds in kmemdup_nul+0x43/0x80 Read of size 8193 at addr ffff888104d10000 by task kworker/1:1/50 Workqueue: isert_login_wq iscsi_target_do_login_rx __asan_memcpy+0x23/0x60 kmemdup_nul+0x43/0x80 iscsi_decode_text_input+0xc6/0x11c0 iscsi_target_do_login+0x261/0x1470 iscsi_target_do_login_rx+0x51d/0x7d0
iscsit over TCP is not exposed: iscsit_get_login_rx() validates the declared length with iscsi_target_check_login_request() and then reads exactly that many bytes off the socket, so the declared length governs how much arrives rather than how much is copied out of an already-filled buffer. isert does not call iscsi_target_check_login_request() at all.
Reject a login PDU whose declared DataSegmentLength exceeds what was received, in both paths that reach isert_rx_login_req():isert_get_login_rx() for the first login PDU and isert_login_recv_done() for the ones after it. dlength <= login_req_len is allowed because the received count can include up to three bytes of iSCSI padding.
Once the check is in place the copy out can no longer exceed the copy in:
the posted login SGE is ISER_RX_PAYLOAD_SIZE, so login_req_len cannot exceed MAX_KEY_VALUE_PAIRS and the min() in isert_rx_login_req() is login_req_len.
Like the existing short-PDU check added by 29e7b925ae6d, the reject in isert_login_recv_done() returns without completing login_req_comp, so a malformed subsequent PDU leaves the login to be torn down by the login timer rather than failing immediately. The first-PDU path returns an error and fails straight away.
Reproduced on 7.2.0-rc4 with soft-RoCE (rdma_rxe) under KASAN, using an initiator that sends the real key=value payload while declaring 8193 in the BHS, on the first login PDU and on the second in separate runs. The reported read size tracks the declared value exactly; 16384 and 61440 behave the same. Unpatched 3 of 3 runs report on each of the two paths, patched 0 of 3 on both, run alternately in a single session, and a normal login still completes on the patched build.
--- drivers/infiniband/ulp/isert/ib_isert.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-)
drivers/infiniband/ulp/isert/ib_isert.c +24 -1
@@ -973,6 +973,21 @@ isert_put_login_tx(struct iscsit_conn *conn, struct iscsi_login *login,return 0 ; } +static int +isert_check_login_req (struct isert_conn *isert_conn) +{ +struct iscsi_hdr *hdr =isert_get_iscsi_hdr (isert_conn->login_desc); +u32 dlength =ntoh24 (hdr->dlength); + +if (unlikely (dlength > (u32 )isert_conn->login_req_len)) { +isert_dbg ("login PDU declares %u data bytes but only %d were received\n" , + dlength, isert_conn->login_req_len); +return -EINVAL ; + } + +return 0 ; +} +static void isert_rx_login_req (struct isert_conn *isert_conn) {
@@ -1411,8 +1426,12 @@ isert_login_recv_done(struct ib_cq *cq, struct ib_wc *wc)if (isert_conn->conn) {struct iscsi_login *login = isert_conn->conn->conn_login; -if (login && !login->first_request) +if (login && !login->first_request) { +if (isert_check_login_req (isert_conn)) +return ; +isert_rx_login_req (isert_conn); + } }mutex_lock (&isert_conn->mutex);
@@ -2377,6 +2396,10 @@ isert_get_login_rx(struct iscsit_conn *conn, struct iscsi_login *login)if (!login->first_request)return 0 ; + ret =isert_check_login_req (isert_conn); +if (ret) +return ret; +isert_rx_login_req (isert_conn);isert_info ("before login_comp conn: %p\n" , conn);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 728/1376 nvme-fc: unmap cmd_iu DMA on rsp_iu mapping failure in init_request
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guixin Liu <[email protected]>
[ Upstream commit f49d0c3a8d56a7cda1628ae17341a4a42063563c ]
__nvme_fc_init_request() maps cmd_iu and then rsp_iu for DMA. If the rsp_iu mapping fails, the original code only recorded the error and fell
through: it left the already-mapped cmd_iu unmapped and still marked the op as FCPOP_STATE_IDLE before returning. Since blk-mq does not call .exit_request() when .init_request() fails, the cmd_iu mapping is leaked for every op whose rsp_iu mapping fails.
Jump to an error path on rsp_iu mapping failure that unmaps cmd_iu and returns the error without marking the op idle, so it stays in the FCPOP_STATE_UNINIT state set by the initial memset().
--- drivers/nvme/host/fc.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/nvme/host/fc.c +6 -0
@@ -2092,9 +2092,15 @@ __nvme_fc_init_request(struct nvme_fc_ctrl *ctrl,dev_err (ctrl->dev,"FCP Op failed - rspiu dma mapping failed.\n" ); ret = -EFAULT ; + goto out_unmap; }atomic_set (&op->state,FCPOP_STATE_IDLE ); +return 0 ; + +out_unmap: +fc_dma_unmap_single (ctrl->lport->dev, op->fcp_req.cmddma, +sizeof (op->cmd_iu),DMA_TO_DEVICE ); out_on_error:return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 729/1376 spi: davinci: switch to managed controller allocation
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
[ Upstream commit ea408a05dc8f18b4a184b88d6e19d2fd1acc1527 ]
The controller is allocated with the non-managed spi_alloc_host() while the interrupt is registered with devm_request_threaded_irq(). During removal, spi_bitbang_stop() only unregisters the controller; the subsequent spi_controller_put() then frees the controller together with its embedded davinci_spi devdata, which is the IRQ handler's dev_id. The devm_request_threaded_irq() release action (free_irq()), which drains the handler, does not run until after .remove() returns. A late or latched interrupt can therefore reach davinci_spi_irq() and dereference already-freed memory.
Switch to devm_spi_alloc_host() so that the devres LIFO order releases the controller only after free_irq() has drained the handler, and drop the now-redundant spi_controller_put() from .remove(). The probe error path is simplified to direct returns.
The clock is acquired with devm_clk_get_enabled(), which is registered after the IRQ and thus released before it by the devres LIFO order. Drain the interrupt explicitly with devm_free_irq() before disabling the controller so that a late interrupt cannot access the registers of a clock-gated controller.
This issue was found by an in-house static analysis tool.
--- drivers/spi/spi-davinci.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
drivers/spi/spi-davinci.c +3 -4
@@ -868,7 +868,7 @@ static int davinci_spi_probe(struct platform_device *pdev)int ret =0 ;u32 spipc0; - host =spi_alloc_host (&pdev->dev,sizeof (struct davinci_spi )); + host =devm_spi_alloc_host (&pdev->dev,sizeof (struct davinci_spi ));if (host ==NULL ) { ret = -ENOMEM ; goto err;
@@ -998,7 +998,6 @@ static int davinci_spi_probe(struct platform_device *pdev)dma_release_channel (dspi->dma_tx); } free_host: -spi_controller_put (host); err:return ret; }
@@ -1022,6 +1021,8 @@ static void davinci_spi_remove(struct platform_device *pdev)spi_bitbang_stop (&dspi->bitbang); +devm_free_irq (&pdev->dev, dspi->irq, dspi); +/* This bit needs to be cleared to disable dpsi->clk */ clear_io_bits (dspi->base +SPIGCR1 ,SPIGCR1_POWERDOWN_MASK );
@@ -1029,8 +1030,6 @@ static void davinci_spi_remove(struct platform_device *pdev)dma_release_channel (dspi->dma_rx);dma_release_channel (dspi->dma_tx); } - -spi_controller_put (host); }static struct platform_driver davinci_spi_driver = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 730/1376 wifi: ath11k: fix overreads in ath11k_wmi_process_csa_switch_count_event()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Johnson <[email protected]>
[ Upstream commit 208d7fdb85976a737a715b81d54efaff6703880c ]
There is no policy entry for WMI_TAG_PDEV_CSA_SWITCH_COUNT_STATUS_EVENT, so the parse infrastructure does not enforce a minimum length for the event struct. Additionally, the num_vdevs field is taken directly from firmware and used as a loop bound over the vdev_ids array without checking that it fits within the TLV payload. Either condition can cause an out-of-bounds read.
Add a TLV policy entry for WMI_TAG_PDEV_CSA_SWITCH_COUNT_STATUS_EVENT so the parse infrastructure enforces a minimum length for the fixed-size event struct. Add a helper ath11k_wmi_tlv_data_len() to recover the payload length of a parsed TLV from the header preceding its data pointer. Use it in ath11k_wmi_process_csa_switch_count_event() to bound num_vdevs before the loop.
Compile tested only.
--- drivers/net/wireless/ath/ath11k/wmi.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-)
drivers/net/wireless/ath/ath11k/wmi.c +19 -2
@@ -159,6 +159,8 @@ static const struct wmi_tlv_policy wmi_tlv_policies[] = { .min_len = sizeof(struct ath11k_wmi_p2p_noa_info) }, [WMI_TAG_P2P_NOA_EVENT] = { .min_len = sizeof(struct wmi_p2p_noa_event) }, + [WMI_TAG_PDEV_CSA_SWITCH_COUNT_STATUS_EVENT] = { + .min_len = sizeof(struct wmi_pdev_csa_switch_ev) }, };#define PRIMAP (_hw_mode_) \
@@ -262,6 +264,13 @@ const void **ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab,return tb; } +static u32 ath11k_wmi_tlv_data_len (const void *data) +{ +const struct wmi_tlv *tlv = (const struct wmi_tlv *)data -1 ; + +return FIELD_GET (WMI_TLV_LEN , tlv->header); +} +static int ath11k_wmi_cmd_send_nowait (struct ath11k_pdev_wmi *wmi,struct sk_buff *skb,u32 cmd_id) {
@@ -8302,15 +8311,23 @@ ath11k_wmi_process_csa_switch_count_event(struct ath11k_base *ab,const struct wmi_pdev_csa_switch_ev *ev, const u32 *vdev_ids) { - int i; + u32 vdev_ids_len = ath11k_wmi_tlv_data_len(vdev_ids); +u32 num_vdevs = ev->num_vdevs;struct ath11k_vif *arvif; +int i;/* Finish CSA once the switch count becomes NULL */ if (ev->current_switch_count)return ; +if (num_vdevs > vdev_ids_len /sizeof (*vdev_ids)) { +ath11k_warn (ab,"csa switch count num_vdevs %u exceeds tlv array length %u\n" , + num_vdevs, vdev_ids_len); +return ; + } +rcu_read_lock (); -for (i =0 ; i < ev->num_vdevs; i++) { +for (i =0 ; i < num_vdevs; i++) { arvif =ath11k_mac_get_arvif_by_vdev_id (ab, vdev_ids[i]);if (!arvif) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 731/1376 PCI: starfive: Fix Runtime PM handling and teardown ordering
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ali Tariq <[email protected]>
[ Upstream commit fb9f7973473fc30d62e0f5f90d59df8ef5223777 ]
The starfive_pcie_remove() path incorrectly disabled runtime PM before executing plda_pcie_host_deinit(), which can cause unmanaged hardware register access in plda_pcie_host_deinit() while power domains or clocks are disabled.
Fix this by restructuring starfive_pcie_remove() to deinitialize the host controller first while runtime PM is active, followed by a synchronous pm_runtime_put_sync() and pm_runtime_disable().
This bug was found in automated AI review by sashiko-bot.
--- drivers/pci/controller/plda/pcie-starfive.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/pci/controller/plda/pcie-starfive.c +2 -2
@@ -431,9 +431,9 @@ static void starfive_pcie_remove(struct platform_device *pdev) {struct starfive_jh7110_pcie *pcie =platform_get_drvdata (pdev); -pm_runtime_put (&pdev->dev); -pm_runtime_disable (&pdev->dev);plda_pcie_host_deinit (&pcie->plda); +pm_runtime_put_sync (&pdev->dev); +pm_runtime_disable (&pdev->dev);platform_set_drvdata (pdev,NULL ); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 732/1376 PCI: starfive: Fix unchecked pm_runtime_get_sync() in probe
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ali Tariq <[email protected]>
[ Upstream commit aaae917990623a6ca6b638557056606a1ae4a8d6 ]
pm_runtime_get_sync() is called in starfive_pcie_probe() without checking its return value. If runtime resume fails, the driver proceeds to configure PCIe hardware through regmap_update_bits(), enable clocks and resets, and power on the PHY, even though the device may not actually be powered.
pm_runtime_get_sync() also increments the usage counter even when resume fails, which would leave the counter unbalanced if this error path were later handled without additional cleanup.
Switch to pm_runtime_resume_and_get(), which balances the usage counter internally on failure, and bail out of probe before any hardware is touched if resume does not succeed.
Tested on StarFive VisionFive 2 v1.2A board.
--- drivers/pci/controller/plda/pcie-starfive.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/pci/controller/plda/pcie-starfive.c +5 -1
@@ -405,7 +405,11 @@ static int starfive_pcie_probe(struct platform_device *pdev)return ret;pm_runtime_enable (&pdev->dev); -pm_runtime_get_sync (&pdev->dev); + ret =pm_runtime_resume_and_get (&pdev->dev); +if (ret <0 ) { +pm_runtime_disable (&pdev->dev); +return dev_err_probe (dev, ret,"failed to resume device\n" ); + } plda->host_ops = &sf_host_ops; plda->num_events =PLDA_MAX_EVENT_NUM ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 733/1376 platform/chrome: cros_ec_debugfs: Clean up console log on probe failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hongyan Xu <[email protected]>
[ Upstream commit 5d187600c4603b8f7812b12ce359a11ad7a7fd3a ]
Add a dedicated error label for failures after successful console log setup.
--- drivers/platform/chrome/cros_ec_debugfs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/platform/chrome/cros_ec_debugfs.c +3 -1
@@ -525,7 +525,7 @@ static int cros_ec_debugfs_probe(struct platform_device *pd) ret =blocking_notifier_chain_register (&ec->ec_dev->panic_notifier, &debug_info->notifier_panic);if (ret) - goto remove_debugfs; + goto cleanup_console_log; ec->debug_info = debug_info;
@@ -533,6 +533,8 @@ static int cros_ec_debugfs_probe(struct platform_device *pd)return 0 ; +cleanup_console_log: +cros_ec_cleanup_console_log (debug_info); remove_debugfs:debugfs_remove_recursive (debug_info->dir);return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 734/1376 platform/chrome: cros_ec_debugfs: Unregister panic notifier
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hongyan Xu <[email protected]>
[ Upstream commit e5954d3031fb55dd31aa59bae477d63c68e941c0 ]
cros_ec_debugfs_probe() registers notifier_panic with the EC panic notifier chain. The remove path tears down debugfs and the console log, but leaves the notifier registered. A later panic notification can call back into the removed instance and queue work that accesses released data.
Unregister the panic notifier before tearing down the debugfs and console log state.
This issue was found by a static analysis tool.
--- drivers/platform/chrome/cros_ec_debugfs.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/platform/chrome/cros_ec_debugfs.c +2 -0
@@ -544,6 +544,8 @@ static void cros_ec_debugfs_remove(struct platform_device *pd) {struct cros_ec_dev *ec =dev_get_drvdata (pd->dev.parent); +blocking_notifier_chain_unregister (&ec->ec_dev->panic_notifier, + &ec->debug_info->notifier_panic);debugfs_remove_recursive (ec->debug_info->dir);cros_ec_cleanup_console_log (ec->debug_info); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 735/1376 wifi: rtlwifi: pci: fix error path in rtl_pci_probe()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abdun Nihaal <[email protected]>
[ Upstream commit 3c2999d13eeb222ae56631aeb7ca248090f2b210 ]
In the last error path in rtl_pci_probe(), the cleanup functions are skipped due to a wrong goto label. Moreover, the successful call to rtl_init_rfkill(), ieee80211_register_hw(), rtl_debug_add_one() have to be reverted. Fix this issue by updating the labels and adding the relevant cleanup functions to the last error path.
--- drivers/net/wireless/realtek/rtlwifi/pci.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/net/wireless/realtek/rtlwifi/pci.c +5 -1
@@ -2226,13 +2226,17 @@ int rtl_pci_probe(struct pci_dev *pdev,rtl_dbg (rtlpriv,COMP_INIT ,DBG_DMESG ,"%s: failed to register IRQ handler\n" ,wiphy_name (hw->wiphy)); - goto fail3; + goto fail6; } rtlpci->irq_alloc =1 ;set_bit (RTL_STATUS_INTERFACE_START , &rtlpriv->status);return 0 ; +fail6: +rtl_deinit_rfkill (hw); +rtl_debug_remove_one (hw); +ieee80211_unregister_hw (hw); fail5:rtl_pci_deinit (hw); fail4:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 736/1376 bus: mhi: host: Flush the posted write after writing to MHI_SOC_RESET_REQ_OFFSET
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <[email protected]>
[ Upstream commit 24f4423cbc89548def2b05ae86de6175086dbf94 ]
mhi_soc_reset() tries to reset the device by writing to the MHI_SOC_RESET_REQ_OFFSET register. But it doesn't do a read-back to ensure that the write gets flushed to the device before returning to the caller.
This may lead to the delay (if implemented) on the caller to be insufficient, if the posted write doesn't reach the device before the delay.
So add a read-back after writing to the MHI_SOC_RESET_REQ_OFFSET register.
--- drivers/bus/mhi/host/main.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/bus/mhi/host/main.c +6 -0
@@ -170,6 +170,9 @@ EXPORT_SYMBOL_GPL(mhi_get_mhi_state);void mhi_soc_reset (struct mhi_controller *mhi_cntrl) { +int __maybe_unused ret; +u32 tmp; +if (mhi_cntrl->reset) { mhi_cntrl->reset (mhi_cntrl);return ;
@@ -178,6 +181,9 @@ void mhi_soc_reset(struct mhi_controller *mhi_cntrl)/* Generic MHI SoC reset */ mhi_write_reg (mhi_cntrl, mhi_cntrl->regs,MHI_SOC_RESET_REQ_OFFSET ,MHI_SOC_RESET_REQ ); +/* Flush the posted write to the device (ignore return value) */ + ret =mhi_read_reg (mhi_cntrl, mhi_cntrl->regs,MHI_SOC_RESET_REQ_OFFSET , + &tmp); }EXPORT_SYMBOL_GPL (mhi_soc_reset);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 737/1376 bus: mhi: host: Fix controller cleanup on EDL sysfs failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuho Choi <[email protected]>
[ Upstream commit 0d5b9e66591d4e2a4376ac82c8cda889a29ba3ee ]
mhi_register_controller() adds the controller device before creating the optional trigger_edl sysfs file. If sysfs_create_file() fails, the error path only drops the device reference and leaves the device registered.
Hence, call device_del() in the error path before put_device().
--- drivers/bus/mhi/host/init.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/bus/mhi/host/init.c +3 -1
@@ -1042,7 +1042,7 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl,if (mhi_cntrl->edl_trigger) { ret =sysfs_create_file (&mhi_dev->dev.kobj, &dev_attr_trigger_edl.attr);if (ret) - goto err_release_dev; + goto err_del_dev; } mhi_cntrl->mhi_dev = mhi_dev;
@@ -1051,6 +1051,8 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl,return 0 ; +err_del_dev: +device_del (&mhi_dev->dev); err_release_dev:put_device (&mhi_dev->dev); error_setup_irq:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 738/1376 md/raid5: protect bitmap batch counters aka seq_flush/seq_write consistency
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chen Cheng <[email protected]>
[ Upstream commit f565925810cb8bc799421485770e15d922ef766a ]
kcsan detect race :
- raid5d() closes the current bitmap batch by updating
conf->seq_flush under conf->device_lock. - __add_stripe_bio() read conf->seq_flush without that lock when assigning sh->bm_seq.
so, protect seq_flush/seq_write consistency for multiple CPUs by READ_ONCE()/WRITE_ONCE() under the path without held device_lock.
re-explain the stripe batch sequence number update flow:
1. sh->bm_seq declare which batch number the stripe belongs to when perform bitmap-related write.
==> bm_seq = seq_flush+1
2. stripe be handled,
* if sh->bm_seq - conf->seq_write > 0, means the batch stripes **newer than** the last written batch, it cannot proceed yet, queued on bitmap_list.
* otherwise , has already proceed.
3. raid5d() ++seq_flush to closes the current batch, means
* no more stripes join that old batch
* just-closed batch ready to write-out to disk
4. raid5d() calls bitmap hooks unplug() or writeout, then, ++seq_write to the same as bm_seq.
- seq_flush - for producer, to close batches.
- seq_write - for consumer, the checkpoint number.
the report:
====================================
BUG: KCSAN: data-race in __add_stripe_bio / raid5d
write to 0xffff88ba5625d470 of 4 bytes by task 82401 on cpu 0:
raid5d+0x1d9/0xba0 [.....]
read to 0xffff88ba5625d470 of 4 bytes by task 82421 on cpu 8:
__add_stripe_bio+0x332/0x400 raid5_make_request+0x6ac/0x2930 md_handle_request+0x4a2/0xa40 md_submit_bio+0x109/0x1a0 __submit_bio+0x2ec/0x390 [.....]
v1 -> v2:
- remove WRITE_ONCE(conf->seq_write) in held device_lock path.
- remove READ_ONCE(conf->seq_flush) in held device_lock path.
--- drivers/md/raid5.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/md/raid5.c +6 -4
@@ -3545,7 +3545,7 @@ static void __add_stripe_bio(struct stripe_head *sh, struct bio *bi, sh->dev[dd_idx].sector);if (conf->mddev->bitmap && firstwrite && !sh->batch_head) { - sh->bm_seq = conf->seq_flush+1 ; + sh->bm_seq =READ_ONCE (conf->seq_flush) +1 ;set_bit (STRIPE_BIT_DELAY , &sh->state); } }
@@ -5751,7 +5751,7 @@ static void make_discard_request(struct mddev *mddev, struct bio *bi) }spin_unlock_irq (&sh->stripe_lock);if (conf->mddev->bitmap) { - sh->bm_seq = conf->seq_flush +1 ; + sh->bm_seq =READ_ONCE (conf->seq_flush) +1 ;set_bit (STRIPE_BIT_DELAY , &sh->state); }
@@ -6788,11 +6788,13 @@ static void raid5d(struct md_thread *thread)if ( !list_empty (&conf->bitmap_list)) {/* Now is a good time to flush some bitmap updates */ - conf->seq_flush++; +int seq = conf->seq_flush +1 ; + +WRITE_ONCE (conf->seq_flush, seq);spin_unlock_irq (&conf->device_lock); mddev->bitmap_ops->unplug (mddev, true);spin_lock_irq (&conf->device_lock); - conf->seq_write = conf->seq_flush; + conf->seq_write = seq;activate_bit_delay (conf, conf->temp_inactive_list); }raid5_activate_delayed (conf);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 739/1376 md/raid5-ppl: fix use-after-free in ppl_do_flush()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sajal Gupta <[email protected]>
[ Upstream commit 371f7a1b392edc8b7cf449cc7713179b588f2d0e ]
The loop in ppl_do_flush() continues iterating after calling ppl_io_unit_finished(), touching io->pending_flushes and leading to a use-after-free.
Add a break statement to stop the loop once io is freed.
--- drivers/md/raid5-ppl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/md/raid5-ppl.c +3 -1
@@ -643,8 +643,10 @@ static void ppl_do_flush(struct ppl_io_unit *io) log->disk_flush_bitmap =0 ;for (i = flushed_disks ; i < raid_disks; i++) { -if (atomic_dec_and_test (&io->pending_flushes)) +if (atomic_dec_and_test (&io->pending_flushes)) {ppl_io_unit_finished (io); +break ; + } } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 740/1376 md: ensure resync is prioritized over recovery
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Li Nan <[email protected]>
[ Upstream commit 4b10a3bc67c1232f76aa1e04778ca26d6c0ddf7f ]
If a new disk is added during resync, the resync process is interrupted, and recovery is triggered, causing the previous resync to be lost. In reality, disk addition should not terminate resync, fix it.
Steps to reproduce the issue:
mdadm -CR /dev/md0 -l1 -n3 -x1 /dev/sd[abcd]
mdadm --fail /dev/md0 /dev/sdc
Stable-dep-of: a47431dfb353 ("md/raid5: protect lockless recovery_offset accesses during reshape")
--- drivers/md/md.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
drivers/md/md.c +7 -7
@@ -9488,6 +9488,13 @@ static bool md_choose_sync_action(struct mddev *mddev, int *spares)return true; } +/* Check if resync is in progress. */ +if (mddev->recovery_cp < MaxSector) { +set_bit (MD_RECOVERY_SYNC , &mddev->recovery); +clear_bit (MD_RECOVERY_RECOVER , &mddev->recovery); +return true; + } +/* * Remove any failed drives, then add spares if possible. Spares are * also removed and re-added, to allow the personality to fail the
@@ -9504,13 +9511,6 @@ static bool md_choose_sync_action(struct mddev *mddev, int *spares)return true; } -/* Check if recovery is in progress. */ -if (mddev->recovery_cp < MaxSector) { -set_bit (MD_RECOVERY_SYNC , &mddev->recovery); -clear_bit (MD_RECOVERY_RECOVER , &mddev->recovery); -return true; - } -/* Delay to choose resync/check/repair in md_do_sync(). */ if (test_bit (MD_RECOVERY_SYNC , &mddev->recovery))return true;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 741/1376 md: allow removing faulty rdev during resync
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zheng Qixing <[email protected]>
[ Upstream commit c0ffeb648000acdc932da7a9d33fd65e9263c54c ]
During RAID resync, faulty rdev cannot be removed and will result in "Device or resource busy" error when attempting hot removal.
Reproduction steps:
mdadm -Cv /dev/md0 -l1 -n3 -e1.2 /dev/sd{b..d}
mdadm /dev/md0 -f /dev/sdb
mdadm /dev/md0 -r /dev/sdb
-> mdadm: hot remove failed for /dev/sdb: Device or resource busy
After commit 4b10a3bc67c1 ("md: ensure resync is prioritized over recovery"), when a device becomes faulty during resync, the md_choose_sync_action() function returns early without calling remove_and_add_spares(), preventing faulty device removal.
This patch extracts a helper function remove_spares() to support removing faulty devices during RAID resync operations.
Stable-dep-of: a47431dfb353 ("md/raid5: protect lockless recovery_offset accesses during reshape")
--- drivers/md/md.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-)
drivers/md/md.c +17 -7
@@ -9424,17 +9424,11 @@ static bool md_spares_need_change(struct mddev *mddev)return false; } -static int remove_and_add_spares (struct mddev *mddev, -struct md_rdev *this) +static int remove_spares (struct mddev *mddev,struct md_rdev *this) {struct md_rdev *rdev; -int spares =0 ;int removed =0 ; -if (this &&test_bit (MD_RECOVERY_RUNNING , &mddev->recovery)) -/* Mustn't remove devices when resync thread is running */ -return 0 ; -rdev_for_each (rdev, mddev) {if ((this ==NULL || rdev == this) &&rdev_removeable (rdev) && !mddev->pers->hot_remove_disk (mddev, rdev)) {
@@ -9448,6 +9442,21 @@ static int remove_and_add_spares(struct mddev *mddev,if (removed && mddev->kobj.sd)sysfs_notify_dirent_safe (mddev->sysfs_degraded); +return removed; +} + +static int remove_and_add_spares (struct mddev *mddev, +struct md_rdev *this) +{ +struct md_rdev *rdev; +int spares =0 ; +int removed =0 ; + +if (this &&test_bit (MD_RECOVERY_RUNNING , &mddev->recovery)) +/* Mustn't remove devices when resync thread is running */ +return 0 ; + + removed =remove_spares (mddev, this);if (this && removed) goto no_add;
@@ -9490,6 +9499,7 @@ static bool md_choose_sync_action(struct mddev *mddev, int *spares)/* Check if resync is in progress. */ if (mddev->recovery_cp < MaxSector) { +remove_spares (mddev,NULL );set_bit (MD_RECOVERY_SYNC , &mddev->recovery);clear_bit (MD_RECOVERY_RECOVER , &mddev->recovery);return true;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 742/1376 md: rename recovery_cp to resync_offset
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Li Nan <[email protected]>
[ Upstream commit 907a99c314a5a695e35acff78ac61f4ec950a6d3 ]
'recovery_cp' was used to represent the progress of sync, but its name contains recovery, which can cause confusion. Replaces 'recovery_cp' with 'resync_offset' for clarity.
Stable-dep-of: a47431dfb353 ("md/raid5: protect lockless recovery_offset accesses during reshape")
--- drivers/md/dm-raid.c | 42 ++++++++++++++-------------- drivers/md/md-bitmap.c | 8 +++--- drivers/md/md-cluster.c | 16 +++++------ drivers/md/md.c | 50 +++++++++++++++++----------------- drivers/md/md.h | 2 +- drivers/md/raid0.c | 6 ++-- drivers/md/raid1-10.c | 2 +- drivers/md/raid1.c | 10 +++---- drivers/md/raid10.c | 16 +++++------ drivers/md/raid5-ppl.c | 6 ++-- drivers/md/raid5.c | 30 ++++++++++---------- include/uapi/linux/raid/md_p.h | 2 +- 12 files changed, 95 insertions(+), 95 deletions(-)
drivers/md/dm-raid.c +21 -21
@@ -438,7 +438,7 @@ static bool rs_is_reshapable(struct raid_set *rs)/* Return true, if raid set in @rs is recovering */ static bool rs_is_recovering (struct raid_set *rs) { -return rs->md.recovery_cp < rs->md.dev_sectors; +return rs->md.resync_offset < rs->md.dev_sectors; }/* Return true, if raid set in @rs is reshaping */
@@ -768,7 +768,7 @@ static struct raid_set *raid_set_alloc(struct dm_target *ti, struct raid_type *r rs->md.layout = raid_type->algorithm; rs->md.new_layout = rs->md.layout; rs->md.delta_disks =0 ; - rs->md.recovery_cp = MaxSector; + rs->md.resync_offset = MaxSector;for (i =0 ; i < raid_devs; i++)md_rdev_init (&rs->dev[i].rdev);
@@ -912,7 +912,7 @@ static int parse_dev_params(struct raid_set *rs, struct dm_arg_set *as) rs->md.external =0 ; rs->md.persistent =1 ; rs->md.major_version =2 ; - }else if (rebuild && !rs->md.recovery_cp) { + }else if (rebuild && !rs->md.resync_offset) {/* * Without metadata, we will not be able to tell if the array * is in-sync or not - we must assume it is not. Therefore,
@@ -1699,20 +1699,20 @@ static void rs_setup_recovery(struct raid_set *rs, sector_t dev_sectors) {/* raid0 does not recover */ if (rs_is_raid0 (rs)) - rs->md.recovery_cp = MaxSector; + rs->md.resync_offset = MaxSector;/* * A raid6 set has to be recovered either * completely or for the grown part to * ensure proper parity and Q-Syndrome */ else if (rs_is_raid6 (rs)) - rs->md.recovery_cp = dev_sectors; + rs->md.resync_offset = dev_sectors;/* * Other raid set types may skip recovery * depending on the 'nosync' flag. */ else - rs->md.recovery_cp =test_bit (__CTR_FLAG_NOSYNC, &rs->ctr_flags) + rs->md.resync_offset =test_bit (__CTR_FLAG_NOSYNC, &rs->ctr_flags) ? MaxSector : dev_sectors; }
@@ -2147,7 +2147,7 @@ static void super_sync(struct mddev *mddev, struct md_rdev *rdev) sb->events =cpu_to_le64 (mddev->events); sb->disk_recovery_offset =cpu_to_le64 (rdev->recovery_offset); - sb->array_resync_offset =cpu_to_le64 (mddev->recovery_cp); + sb->array_resync_offset =cpu_to_le64 (mddev->resync_offset); sb->level =cpu_to_le32 (mddev->level); sb->layout =cpu_to_le32 (mddev->layout);
@@ -2340,18 +2340,18 @@ static int super_init_validation(struct raid_set *rs, struct md_rdev *rdev) }if (!test_bit (__CTR_FLAG_NOSYNC, &rs->ctr_flags)) - mddev->recovery_cp =le64_to_cpu (sb->array_resync_offset); + mddev->resync_offset =le64_to_cpu (sb->array_resync_offset);/* * During load, we set FirstUse if a new superblock was written. * There are two reasons we might not have a superblock: * 1) The raid set is brand new - in which case, all of the * devices must have their In_sync bit set. Also, -* recovery_cp must be 0, unless forced. +* resync_offset must be 0, unless forced. * 2) This is a new device being added to an old raid set * and the new device needs to be rebuilt - in which * case the In_sync bit will /not/ be set and -* recovery_cp must be MaxSector. +* resync_offset must be MaxSector. * 3) This is/are a new device(s) being added to an old * raid set during takeover to a higher raid level * to provide capacity for redundancy or during reshape
@@ -2396,8 +2396,8 @@ static int super_init_validation(struct raid_set *rs, struct md_rdev *rdev) new_devs > 1 ? "s" : "");return -EINVAL ; }else if (!test_bit (__CTR_FLAG_REBUILD, &rs->ctr_flags) &&rs_is_recovering (rs)) { -DMERR ("'rebuild' specified while raid set is not in-sync (recovery_cp=%llu)" , - (unsigned long long ) mddev->recovery_cp); +DMERR ("'rebuild' specified while raid set is not in-sync (resync_offset=%llu)" , + (unsigned long long ) mddev->resync_offset);return -EINVAL ; }else if (rs_is_reshaping (rs)) { DMERR("'rebuild' specified while raid set is being reshaped (reshape_position=%llu)",
@@ -2702,11 +2702,11 @@ static int rs_adjust_data_offsets(struct raid_set *rs) } out:/* -* Raise recovery_cp in case data_offset != 0 to +* Raise resync_offset in case data_offset != 0 to * avoid false recovery positives in the constructor. */ -if (rs->md.recovery_cp < rs->md.dev_sectors) - rs->md.recovery_cp += rs->dev[0 ].rdev.data_offset; +if (rs->md.resync_offset < rs->md.dev_sectors) + rs->md.resync_offset += rs->dev[0 ].rdev.data_offset;/* Adjust data offsets on all rdevs but on any raid4/5/6 journal device */ rdev_for_each (rdev, &rs->md) {
@@ -2761,7 +2761,7 @@ static int rs_setup_takeover(struct raid_set *rs) }clear_bit (MD_ARRAY_FIRST_USE , &mddev->flags); - mddev->recovery_cp = MaxSector; + mddev->resync_offset = MaxSector;while (d--) { rdev = &rs->dev[d].rdev;
@@ -2769,7 +2769,7 @@ static int rs_setup_takeover(struct raid_set *rs)if (test_bit (d, (void *) rs->rebuild_disks)) {clear_bit (In_sync, &rdev->flags);clear_bit (Faulty, &rdev->flags); - mddev->recovery_cp = rdev->recovery_offset =0 ; + mddev->resync_offset = rdev->recovery_offset =0 ;/* Bitmap has to be created when we do an "up" takeover */ set_bit (MD_ARRAY_FIRST_USE , &mddev->flags); }
@@ -3227,7 +3227,7 @@ static int raid_ctr(struct dm_target *ti, unsigned int argc, char **argv)if (r) goto bad; -rs_setup_recovery (rs, rs->md.recovery_cp < rs->md.dev_sectors ? rs->md.recovery_cp : rs->md.dev_sectors); +rs_setup_recovery (rs, rs->md.resync_offset < rs->md.dev_sectors ? rs->md.resync_offset : rs->md.dev_sectors); }else {/* This is no size change or it is shrinking, update size and record in superblocks */ r =rs_set_dev_and_array_sectors (rs, rs->ti->len, false);
@@ -3449,7 +3449,7 @@ static sector_t rs_get_progress(struct raid_set *rs, unsigned long recovery, }else {if (state == st_idle && !test_bit (MD_RECOVERY_INTR , &recovery)) - r = mddev->recovery_cp; + r = mddev->resync_offset;else r = mddev->curr_resync_completed;
@@ -4079,9 +4079,9 @@ static int raid_preresume(struct dm_target *ti) }/* Check for any resize/reshape on @rs and adjust/initiate */ -if (mddev->recovery_cp && mddev->recovery_cp < MaxSector) { +if (mddev->resync_offset && mddev->resync_offset < MaxSector) {set_bit (MD_RECOVERY_REQUESTED , &mddev->recovery); - mddev->resync_min = mddev->recovery_cp; + mddev->resync_min = mddev->resync_offset;if (test_bit (RT_FLAG_RS_GROW , &rs->runtime_flags)) mddev->resync_max_sectors = mddev->dev_sectors; }
drivers/md/md-bitmap.c +4 -4
@@ -1976,12 +1976,12 @@ static void bitmap_dirty_bits(struct mddev *mddev, unsigned long s,md_bitmap_set_memory_bits (bitmap, sec,1 );md_bitmap_file_set_bit (bitmap, sec); -if (sec < bitmap->mddev->recovery_cp) +if (sec < bitmap->mddev->resync_offset)/* We are asserting that the array is dirty, -* so move the recovery_cp address back so +* so move the resync_offset address back so * that it is obvious that it is dirty */ - bitmap->mddev->recovery_cp = sec; + bitmap->mddev->resync_offset = sec; } }
@@ -2247,7 +2247,7 @@ static int bitmap_load(struct mddev *mddev) || bitmap->events_cleared == mddev->events)/* no need to keep dirty bits to optimise a * re-add of a missing device */ - start = mddev->recovery_cp; + start = mddev->resync_offset;mutex_lock (&mddev->bitmap_info.mutex); err =md_bitmap_init_from_disk (bitmap, start);
drivers/md/md-cluster.c +8 -8
@@ -337,11 +337,11 @@ static void recover_bitmaps(struct md_thread *thread)md_wakeup_thread (mddev->sync_thread);if (hi >0 ) { -if (lo < mddev->recovery_cp) - mddev->recovery_cp = lo; +if (lo < mddev->resync_offset) + mddev->resync_offset = lo;/* wake up thread to continue resync in case resync * is not finished */ -if (mddev->recovery_cp != MaxSector) { +if (mddev->resync_offset != MaxSector) {/* * clear the REMOTE flag since we will launch * resync thread in current node.
@@ -868,9 +868,9 @@ static int gather_all_resync_info(struct mddev *mddev, int total_slots)lockres_free (bm_lockres);continue ; } -if ((hi >0 ) && (lo < mddev->recovery_cp)) { +if ((hi >0 ) && (lo < mddev->resync_offset)) {set_bit (MD_RECOVERY_NEEDED , &mddev->recovery); - mddev->recovery_cp = lo; + mddev->resync_offset = lo;md_check_recovery (mddev); }
@@ -1032,7 +1032,7 @@ static int leave(struct mddev *mddev)* Also, we should send BITMAP_NEEDS_SYNC message in * case reshaping is interrupted. */ -if ((cinfo->slot_number >0 && mddev->recovery_cp != MaxSector) || +if ((cinfo->slot_number >0 && mddev->resync_offset != MaxSector) || (mddev->reshape_position != MaxSector &&test_bit (MD_CLOSING , &mddev->flags)))resync_bitmap (mddev);
@@ -1610,8 +1610,8 @@ static int gather_bitmaps(struct md_rdev *rdev)pr_warn ("md-cluster: Could not gather bitmaps from slot %d" , sn); goto out; } -if ((hi >0 ) && (lo < mddev->recovery_cp)) - mddev->recovery_cp = lo; +if ((hi >0 ) && (lo < mddev->resync_offset)) + mddev->resync_offset = lo; } out:return err;
drivers/md/md.c +25 -25
159 lines not on this page · raw message
drivers/md/md.h +1 -1
@@ -493,7 +493,7 @@ struct mddev {atomic_t recovery_active;/* blocks scheduled, but not written */ wait_queue_head_t recovery_wait; -sector_t recovery_cp; +sector_t resync_offset;sector_t resync_min;/* user requested sync * starts here */ sector_t resync_max;/* resync should pause
drivers/md/raid0.c +3 -3
@@ -676,7 +676,7 @@ static void *raid0_takeover_raid45(struct mddev *mddev) mddev->raid_disks--; mddev->delta_disks =-1 ;/* make sure it will be not marked as dirty */ - mddev->recovery_cp = MaxSector; + mddev->resync_offset = MaxSector;mddev_clear_unsupported_flags (mddev,UNSUPPORTED_MDDEV_FLAGS );create_strip_zones (mddev, &priv_conf);
@@ -719,7 +719,7 @@ static void *raid0_takeover_raid10(struct mddev *mddev) mddev->raid_disks += mddev->delta_disks; mddev->degraded =0 ;/* make sure it will be not marked as dirty */ - mddev->recovery_cp = MaxSector; + mddev->resync_offset = MaxSector;mddev_clear_unsupported_flags (mddev,UNSUPPORTED_MDDEV_FLAGS );create_strip_zones (mddev, &priv_conf);
@@ -762,7 +762,7 @@ static void *raid0_takeover_raid1(struct mddev *mddev) mddev->delta_disks =1 - mddev->raid_disks; mddev->raid_disks =1 ;/* make sure it will be not marked as dirty */ - mddev->recovery_cp = MaxSector; + mddev->resync_offset = MaxSector;mddev_clear_unsupported_flags (mddev,UNSUPPORTED_MDDEV_FLAGS );create_strip_zones (mddev, &priv_conf);
drivers/md/raid1-10.c +1 -1
@@ -283,7 +283,7 @@ static inline int raid1_check_read_range(struct md_rdev *rdev,static inline bool raid1_should_read_first (struct mddev *mddev,sector_t this_sector,int len) { -if ((mddev->recovery_cp < this_sector + len)) +if ((mddev->resync_offset < this_sector + len))return true; if (mddev_is_clustered(mddev) &&
drivers/md/raid1.c +5 -5
@@ -2815,7 +2815,7 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr, }if (mddev->bitmap ==NULL && - mddev->recovery_cp == MaxSector && + mddev->resync_offset == MaxSector && !test_bit (MD_RECOVERY_REQUESTED , &mddev->recovery) && conf->fullsync ==0 ) { *skipped =1 ;
@@ -3277,9 +3277,9 @@ static int raid1_run(struct mddev *mddev) }if (conf->raid_disks - mddev->degraded ==1 ) - mddev->recovery_cp = MaxSector; + mddev->resync_offset = MaxSector; -if (mddev->recovery_cp != MaxSector) +if (mddev->resync_offset != MaxSector)pr_info ("md/raid1:%s: not clean -- starting background reconstruction\n" ,mdname (mddev)); pr_info("md/raid1:%s: active with %d out of %d mirrors\n",
@@ -3340,8 +3340,8 @@ static int raid1_resize(struct mddev *mddev, sector_t sectors)md_set_array_sectors (mddev, newsize);if (sectors > mddev->dev_sectors && - mddev->recovery_cp > mddev->dev_sectors) { - mddev->recovery_cp = mddev->dev_sectors; + mddev->resync_offset > mddev->dev_sectors) { + mddev->resync_offset = mddev->dev_sectors;set_bit (MD_RECOVERY_NEEDED , &mddev->recovery); } mddev->dev_sectors = sectors;
drivers/md/raid10.c +8 -8
@@ -2115,7 +2115,7 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)int last = conf->geo.raid_disks -1 ;struct raid10_info *p; -if (mddev->recovery_cp < MaxSector) +if (mddev->resync_offset < MaxSector)/* only hot-add to in-sync arrays, as recovery is * very different from resync */
@@ -3192,7 +3192,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,* of a clean array, like RAID1 does. */ if (mddev->bitmap == NULL && - mddev->recovery_cp == MaxSector && + mddev->resync_offset == MaxSector && mddev->reshape_position == MaxSector && !test_bit(MD_RECOVERY_SYNC, &mddev->recovery) && !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery) &&
@@ -4154,7 +4154,7 @@ static int raid10_run(struct mddev *mddev) disk->recovery_disabled = mddev->recovery_disabled -1 ; } -if (mddev->recovery_cp != MaxSector) +if (mddev->resync_offset != MaxSector)pr_notice ("md/raid10:%s: not clean -- starting background reconstruction\n" ,mdname (mddev)); pr_info("md/raid10:%s: active with %d out of %d devices\n",
@@ -4254,8 +4254,8 @@ static int raid10_resize(struct mddev *mddev, sector_t sectors)md_set_array_sectors (mddev, size);if (sectors > mddev->dev_sectors && - mddev->recovery_cp > oldsize) { - mddev->recovery_cp = oldsize; + mddev->resync_offset > oldsize) { + mddev->resync_offset = oldsize;set_bit (MD_RECOVERY_NEEDED , &mddev->recovery); }calc_sectors (conf, sectors);
@@ -4284,7 +4284,7 @@ static void *raid10_takeover_raid0(struct mddev *mddev, sector_t size, int devs) mddev->delta_disks = mddev->raid_disks; mddev->raid_disks *=2 ;/* make sure it will be not marked as dirty */ - mddev->recovery_cp = MaxSector; + mddev->resync_offset = MaxSector; mddev->dev_sectors = size; conf =setup_conf (mddev);
@@ -5098,8 +5098,8 @@ static void raid10_finish_reshape(struct mddev *mddev)return ;if (mddev->delta_disks >0 ) { -if (mddev->recovery_cp > mddev->resync_max_sectors) { - mddev->recovery_cp = mddev->resync_max_sectors; +if (mddev->resync_offset > mddev->resync_max_sectors) { + mddev->resync_offset = mddev->resync_max_sectors;set_bit (MD_RECOVERY_NEEDED , &mddev->recovery); } mddev->resync_max_sectors = mddev->array_sectors;
drivers/md/raid5-ppl.c +3 -3
@@ -1165,7 +1165,7 @@ static int ppl_load_distributed(struct ppl_log *log) le64_to_cpu(pplhdr->generation));/* attempt to recover from log if we are starting a dirty array */ -if (pplhdr && !mddev->pers && mddev->recovery_cp != MaxSector) +if (pplhdr && !mddev->pers && mddev->resync_offset != MaxSector) ret =ppl_recover (log, pplhdr, pplhdr_offset);/* write empty header if we are starting the array */
@@ -1424,14 +1424,14 @@ int ppl_init_log(struct r5conf *conf)if (ret) { goto err; - }else if (!mddev->pers && mddev->recovery_cp ==0 && + }else if (!mddev->pers && mddev->resync_offset ==0 && ppl_conf->recovered_entries >0 && ppl_conf->mismatch_count ==0 ) {/* * If we are starting a dirty array and the recovery succeeds * without any issues, set the array as clean. */ - mddev->recovery_cp = MaxSector; + mddev->resync_offset = MaxSector;set_bit (MD_SB_CHANGE_CLEAN , &mddev->sb_flags); }else if (mddev->pers && ppl_conf->mismatch_count >0 ) {/* no mismatch allowed when enabling PPL for a running array */
drivers/md/raid5.c +15 -15
@@ -3748,7 +3748,7 @@ static int want_replace(struct stripe_head *sh, int disk_idx) && !test_bit (Faulty, &rdev->flags) && !test_bit (In_sync, &rdev->flags) && (rdev->recovery_offset <= sh->sector - || rdev->mddev->recovery_cp <= sh->sector)) + || rdev->mddev->resync_offset <= sh->sector)) rv = 1;return rv; }
@@ -3840,7 +3840,7 @@ static int need_this_block(struct stripe_head *sh, struct stripe_head_state *s,* is missing/faulty, then we need to read everything we can. */ if (!force_rcw && - sh->sector < sh->raid_conf->mddev->recovery_cp) + sh->sector < sh->raid_conf->mddev->resync_offset)/* reconstruct-write isn't being forced */ return 0 ;for (i =0 ; i < s->failed && i <2 ; i++) {
@@ -4105,7 +4105,7 @@ static int handle_stripe_dirtying(struct r5conf *conf, int disks) {int rmw =0 , rcw =0 , i; -sector_t recovery_cp = conf->mddev->recovery_cp; +sector_t resync_offset = conf->mddev->resync_offset;/* Check whether resync is now happening or should start. * If yes, then the array is dirty (after unclean shutdown or
@@ -4115,14 +4115,14 @@ static int handle_stripe_dirtying(struct r5conf *conf,* generate correct data from the parity. */ if (conf->rmw_level ==PARITY_DISABLE_RMW || - (recovery_cp < MaxSector && sh->sector >= recovery_cp && + (resync_offset < MaxSector && sh->sector >= resync_offset && s->failed ==0 )) {/* Calculate the real rcw later - for now make it * look like rcw is cheaper */ rcw =1 ; rmw =2 ; -pr_debug ("force RCW rmw_level=%u, recovery_cp=%llu sh->sector=%llu\n" , - conf->rmw_level, (unsigned long long )recovery_cp, +pr_debug ("force RCW rmw_level=%u, resync_offset=%llu sh->sector=%llu\n" , + conf->rmw_level, (unsigned long long )resync_offset, (unsigned long long )sh->sector); }else for (i = disks; i--; ) {/* would I have to read this buffer for read_modify_write */
@@ -4779,14 +4779,14 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s)if (test_bit (STRIPE_SYNCING , &sh->state)) {/* If there is a failed device being replaced, * we must be recovering. -* else if we are after recovery_cp, we must be syncing +* else if we are after resync_offset, we must be syncing * else if MD_RECOVERY_REQUESTED is set, we also are syncing. * else we can only be replacing * sync and recovery both need to read all devices, and so * use the same flag. */ if (do_recovery || - sh->sector >= conf->mddev->recovery_cp || + sh->sector >= conf->mddev->resync_offset ||test_bit (MD_RECOVERY_REQUESTED , &(conf->mddev->recovery))) s->syncing =1 ;else
@@ -7811,7 +7811,7 @@ static int raid5_run(struct mddev *mddev)int first =1 ;int ret = -EIO ; -if (mddev->recovery_cp != MaxSector) +if (mddev->resync_offset != MaxSector)pr_notice ("md/raid:%s: not clean -- starting background reconstruction\n" ,mdname (mddev));
@@ -7952,7 +7952,7 @@ static int raid5_run(struct mddev *mddev) mdname(mddev)); mddev->ro =1 ;set_disk_ro (mddev->gendisk,1 ); - }else if (mddev->recovery_cp == MaxSector) + }else if (mddev->resync_offset == MaxSector)set_bit (MD_JOURNAL_CLEAN , &mddev->flags); }
@@ -8019,7 +8019,7 @@ static int raid5_run(struct mddev *mddev) mddev->resync_max_sectors = mddev->dev_sectors;if (mddev->degraded > dirty_parity_disks && - mddev->recovery_cp != MaxSector) { + mddev->resync_offset != MaxSector) {if (test_bit (MD_HAS_PPL , &mddev->flags))pr_crit ("md/raid:%s: starting dirty degraded array with PPL.\n" ,mdname (mddev));
@@ -8360,8 +8360,8 @@ static int raid5_resize(struct mddev *mddev, sector_t sectors)md_set_array_sectors (mddev, newsize);if (sectors > mddev->dev_sectors && - mddev->recovery_cp > mddev->dev_sectors) { - mddev->recovery_cp = mddev->dev_sectors; + mddev->resync_offset > mddev->dev_sectors) { + mddev->resync_offset = mddev->dev_sectors;set_bit (MD_RECOVERY_NEEDED , &mddev->recovery); } mddev->dev_sectors = sectors;
@@ -8455,7 +8455,7 @@ static int raid5_start_reshape(struct mddev *mddev)return -EINVAL ;/* raid5 can't handle concurrent reshape and recovery */ -if (mddev->recovery_cp < MaxSector) +if (mddev->resync_offset < MaxSector)return -EBUSY ;for (i =0 ; i < conf->raid_disks; i++)if (conf->disks[i].replacement)
@@ -8680,7 +8680,7 @@ static void *raid45_takeover_raid0(struct mddev *mddev, int level) mddev->raid_disks +=1 ; mddev->delta_disks =1 ;/* make sure it will be not marked as dirty */ - mddev->recovery_cp = MaxSector; + mddev->resync_offset = MaxSector;return setup_conf (mddev); }
include/uapi/linux/raid/md_p.h +1 -1
@@ -173,7 +173,7 @@ typedef struct mdp_superblock_s {#else #error unspecified endianness#endif -__u32 recovery_cp;/* 11 recovery checkpoint sector count */ +__u32 resync_offset;/* 11 resync checkpoint sector count */ /* There are only valid for minor_version > 90 */ __u64 reshape_position;/* 12,13 next address in array-space for reshape */ __u32 new_level;/* 14 new level we are reshaping to */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 743/1376 md: add a new recovery_flag MD_RECOVERY_LAZY_RECOVER
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yu Kuai <[email protected]>
[ Upstream commit c951ccf0bf2df4f39b45dc77998dd71da7a85369 ]
This flag is used by llbitmap in later patches to skip raid456 initial recover and delay building initial xor data to first write.
https: //lore.kernel.org/linux-raid/[email protected]
Stable-dep-of: a47431dfb353 ("md/raid5: protect lockless recovery_offset accesses during reshape")
--- drivers/md/md.c | 47 +++++++++++++++++++++++++++++++++++++++++++++- drivers/md/md.h | 2 ++ drivers/md/raid5.c | 19 +++++++++++++++---- 3 files changed, 63 insertions(+), 5 deletions(-)
drivers/md/md.c +46 -1
@@ -8907,6 +8907,39 @@ static sector_t md_sync_max_sectors(struct mddev *mddev, } } +/* +* If lazy recovery is requested and all rdevs are in sync, select the rdev with +* the higest index to perfore recovery to build initial xor data, this is the +* same as old bitmap. +*/ +static bool mddev_select_lazy_recover_rdev (struct mddev *mddev) +{ +struct md_rdev *recover_rdev =NULL ; +struct md_rdev *rdev; +bool ret = false; + +rcu_read_lock (); +rdev_for_each_rcu (rdev, mddev) { +if (rdev->raid_disk <0 ) +continue ; + +if (test_bit (Faulty, &rdev->flags) || + !test_bit (In_sync, &rdev->flags)) +break ; + +if (!recover_rdev || recover_rdev->raid_disk < rdev->raid_disk) + recover_rdev = rdev; + } + +if (recover_rdev) { +clear_bit (In_sync, &recover_rdev->flags); + ret = true; + } + +rcu_read_unlock (); +return ret; +} +static sector_t md_sync_position (struct mddev *mddev,enum sync_action action) {sector_t start =0 ;
@@ -8942,6 +8975,14 @@ static sector_t md_sync_position(struct mddev *mddev, enum sync_action action) start = rdev->recovery_offset;rcu_read_unlock (); +/* +* If there are no spares, and raid456 lazy initial recover is +* requested. +*/ +if (test_bit (MD_RECOVERY_LAZY_RECOVER , &mddev->recovery) && + start == MaxSector &&mddev_select_lazy_recover_rdev (mddev)) + start =0 ; +/* If there is a bitmap, we need to make sure all * writes that started before we added a spare * complete before we start doing a recovery.
@@ -9494,6 +9535,7 @@ static bool md_choose_sync_action(struct mddev *mddev, int *spares)set_bit (MD_RECOVERY_RESHAPE , &mddev->recovery);clear_bit (MD_RECOVERY_RECOVER , &mddev->recovery); +clear_bit (MD_RECOVERY_LAZY_RECOVER , &mddev->recovery);return true; }
@@ -9502,6 +9544,7 @@ static bool md_choose_sync_action(struct mddev *mddev, int *spares)remove_spares (mddev,NULL );set_bit (MD_RECOVERY_SYNC , &mddev->recovery);clear_bit (MD_RECOVERY_RECOVER , &mddev->recovery); +clear_bit (MD_RECOVERY_LAZY_RECOVER , &mddev->recovery);return true; }
@@ -9511,7 +9554,7 @@ static bool md_choose_sync_action(struct mddev *mddev, int *spares)* re-add. */ *spares =remove_and_add_spares (mddev,NULL ); -if (*spares) { +if (*spares ||test_bit (MD_RECOVERY_LAZY_RECOVER , &mddev->recovery)) {clear_bit (MD_RECOVERY_SYNC , &mddev->recovery);clear_bit (MD_RECOVERY_CHECK , &mddev->recovery);clear_bit (MD_RECOVERY_REQUESTED , &mddev->recovery);
@@ -9724,6 +9767,7 @@ void md_check_recovery(struct mddev *mddev) }clear_bit (MD_RECOVERY_RECOVER , &mddev->recovery); +clear_bit (MD_RECOVERY_LAZY_RECOVER , &mddev->recovery);clear_bit (MD_RECOVERY_NEEDED , &mddev->recovery);clear_bit (MD_SB_CHANGE_PENDING , &mddev->sb_flags);
@@ -9834,6 +9878,7 @@ void md_reap_sync_thread(struct mddev *mddev)clear_bit (MD_RECOVERY_RESHAPE , &mddev->recovery);clear_bit (MD_RECOVERY_REQUESTED , &mddev->recovery);clear_bit (MD_RECOVERY_CHECK , &mddev->recovery); +clear_bit (MD_RECOVERY_LAZY_RECOVER , &mddev->recovery);/* * We call md_cluster_ops->update_size here because sync_size could * be changed by md_update_sb, and MD_RECOVERY_RESHAPE is cleared,
drivers/md/md.h +2 -0
@@ -634,6 +634,8 @@ enum recovery_flags {MD_RECOVERY_RESHAPE ,/* remote node is running resync thread */ MD_RESYNCING_REMOTE , +/* raid456 lazy initial recover */ + MD_RECOVERY_LAZY_RECOVER, }; enum md_ro_state {
drivers/md/raid5.c +15 -4
@@ -4707,10 +4707,21 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) } }else if (test_bit (In_sync, &rdev->flags))set_bit (R5_Insync, &dev->flags); -else if (sh->sector +RAID5_STRIPE_SECTORS (conf) <= rdev->recovery_offset) -/* in sync if before recovery_offset */ -set_bit (R5_Insync, &dev->flags); -else if (test_bit (R5_UPTODATE , &dev->flags) && +else if (sh->sector +RAID5_STRIPE_SECTORS (conf) <= + rdev->recovery_offset) { +/* +* in sync if: +* - normal IO, or +* - resync IO that is not lazy recovery +* +* For lazy recovery, we have to mark the rdev without +* In_sync as failed, to build initial xor data. +*/ +if (!test_bit (STRIPE_SYNCING , &sh->state) || + !test_bit (MD_RECOVERY_LAZY_RECOVER , + &conf->mddev->recovery)) +set_bit (R5_Insync, &dev->flags); + }else if (test_bit (R5_UPTODATE , &dev->flags) &&test_bit (R5_Expanded, &dev->flags))/* If we've reshaped into here, we assume it is Insync. * We will shortly update recovery_offset to make
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 744/1376 md/raid5: protect lockless recovery_offset accesses during reshape
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chen Cheng <[email protected]>
[ Upstream commit a47431dfb3538a1485f65b68a0605a05307b5b2d ]
During reshape:
- reshape_request() advances rdev->recovery_offset for non-In_sync devices locklessly.
- analyse_stripe() reads rdev->recovery_offset locklessly to decide:
a. use a replacement device to read ?
b. a device can already be treated as in-sync for the current
stripe ?
one possible scenario is:
CPU1 CPU2reshape_request()
-> mddev->curr_resync_completed = sector_nr
-> if (!mddev->reshape_backwards)
-> rdev->recovery_offset = sector_nr
analyse_stripe(sh)
-> rdev = conf->disks[i].replacement
-> if (rdev->recovery_offset >=
sh->sector + stripe_sectors)
set_bit(R5_ReadRepl)
-> or
-> if (sh->sector + stripe_sectors <=
rdev->recovery_offset)
set_bit(R5_Insync)And it could be:
- reading from a replacement before it is recovered far enough; or
- treating a not-yet-recovered device as in-sync for the current stripe.
The race report:
==================================================================
BUG: KCSAN: data-race in ops_run_io / reshape_request
write to 0xffff8bdee168b270 of 8 bytes by task 1704 on cpu 10:
reshape_request+0x1292/0x17b0 raid5_sync_request+0x815/0xa00 md_do_sync.cold+0xf8d/0x1516 [......]
read to 0xffff8bdee168b270 of 8 bytes by task 1696 on cpu 9:
ops_run_io+0xc25/0x1960 handle_stripe+0x2273/0x4570 handle_active_stripes.isra.0+0x6e0/0xa50 raid5d+0x7d5/0xb90 [......]
value changed: 0x0000000000091a00 -> 0x0000000000091b00
==================================================================
--- drivers/md/raid5.c | 50 +++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 25 deletions(-)
drivers/md/raid5.c +25 -25
@@ -3744,11 +3744,10 @@ static int want_replace(struct stripe_head *sh, int disk_idx)int rv =0 ; rdev = sh->raid_conf->disks[disk_idx].replacement; -if (rdev - && !test_bit (Faulty, &rdev->flags) - && !test_bit (In_sync, &rdev->flags) - && (rdev->recovery_offset <= sh->sector - || rdev->mddev->resync_offset <= sh->sector)) +if (rdev && !test_bit (Faulty, &rdev->flags) && + !test_bit (In_sync, &rdev->flags) && + (READ_ONCE (rdev->recovery_offset) <= sh->sector || + rdev->mddev->resync_offset <= sh->sector)) rv =1 ;return rv; }
@@ -4665,7 +4664,8 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s)*/ rdev = conf->disks[i].replacement;if (rdev && !test_bit (Faulty, &rdev->flags) && - rdev->recovery_offset >= sh->sector +RAID5_STRIPE_SECTORS (conf) && +READ_ONCE (rdev->recovery_offset) >= + sh->sector +RAID5_STRIPE_SECTORS (conf) && !rdev_has_badblock (rdev, sh->sector,RAID5_STRIPE_SECTORS (conf)))set_bit (R5_ReadRepl, &dev->flags);
@@ -4708,7 +4708,7 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) }else if (test_bit (In_sync, &rdev->flags))set_bit (R5_Insync, &dev->flags);else if (sh->sector +RAID5_STRIPE_SECTORS (conf) <= - rdev->recovery_offset) { +READ_ONCE (rdev->recovery_offset)) {/* * in sync if: * - normal IO, or
@@ -5441,13 +5441,13 @@ static int raid5_read_one_chunk(struct mddev *mddev, struct bio *raid_bio) rdev = conf->disks[dd_idx].replacement;if (!rdev ||test_bit (Faulty, &rdev->flags) || - rdev->recovery_offset < end_sector) { +READ_ONCE (rdev->recovery_offset) < end_sector) { rdev = conf->disks[dd_idx].rdev;if (!rdev)return 0 ;if (test_bit (Faulty, &rdev->flags) || !(test_bit (In_sync, &rdev->flags) || - rdev->recovery_offset >= end_sector)) +READ_ONCE (rdev->recovery_offset) >= end_sector))return 0 ; }
@@ -6376,8 +6376,8 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *skif (rdev->raid_disk >=0 && !test_bit (Journal, &rdev->flags) && !test_bit (In_sync, &rdev->flags) && - rdev->recovery_offset < sector_nr) - rdev->recovery_offset = sector_nr; +READ_ONCE (rdev->recovery_offset) < sector_nr) +WRITE_ONCE (rdev->recovery_offset, sector_nr); conf->reshape_checkpoint = jiffies;set_bit (MD_SB_CHANGE_DEVS , &mddev->sb_flags);
@@ -6485,8 +6485,8 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *skif (rdev->raid_disk >=0 && !test_bit (Journal, &rdev->flags) && !test_bit (In_sync, &rdev->flags) && - rdev->recovery_offset < sector_nr) - rdev->recovery_offset = sector_nr; +READ_ONCE (rdev->recovery_offset) < sector_nr) +WRITE_ONCE (rdev->recovery_offset, sector_nr); conf->reshape_checkpoint = jiffies;set_bit (MD_SB_CHANGE_DEVS , &mddev->sb_flags);md_wakeup_thread (mddev->thread);
@@ -7996,9 +7996,9 @@ static int raid5_run(struct mddev *mddev)/* Hack because v0.91 doesn't store recovery_offset properly. */ if (mddev->major_version ==0 && mddev->minor_version >90 ) - rdev->recovery_offset = reshape_offset; +WRITE_ONCE (rdev->recovery_offset, reshape_offset); - if (rdev->recovery_offset < reshape_offset) { + if (READ_ONCE(rdev->recovery_offset) < reshape_offset) { /* We need to check old and new layout */ if (!only_parity(rdev->raid_disk, conf->algorithm,
@@ -8149,10 +8149,10 @@ static int raid5_spare_active(struct mddev *mddev)for (i =0 ; i < conf->raid_disks; i++) { rdev = conf->disks[i].rdev; replacement = conf->disks[i].replacement; -if (replacement - && replacement->recovery_offset == MaxSector - && !test_bit (Faulty, &replacement->flags) - && !test_and_set_bit (In_sync, &replacement->flags)) { +if (replacement && +READ_ONCE (replacement->recovery_offset) == MaxSector && + !test_bit (Faulty, &replacement->flags) && + !test_and_set_bit (In_sync, &replacement->flags)) {/* Replacement has just become active. */ if (!rdev || !test_and_clear_bit (In_sync, &rdev->flags))
@@ -8167,10 +8167,10 @@ static int raid5_spare_active(struct mddev *mddev) rdev->sysfs_state); }sysfs_notify_dirent_safe (replacement->sysfs_state); - }else if (rdev - && rdev->recovery_offset == MaxSector - && !test_bit (Faulty, &rdev->flags) - && !test_and_set_bit (In_sync, &rdev->flags)) { + }else if (rdev && +READ_ONCE (rdev->recovery_offset) == MaxSector && + !test_bit (Faulty, &rdev->flags) && + !test_and_set_bit (In_sync, &rdev->flags)) { count++;sysfs_notify_dirent_safe (rdev->sysfs_state); }
@@ -8540,7 +8540,7 @@ static int raid5_start_reshape(struct mddev *mddev) >= conf->previous_raid_disks)set_bit (In_sync, &rdev->flags); else - rdev->recovery_offset = 0; + WRITE_ONCE(rdev->recovery_offset, 0);/* Failure here is OK */ sysfs_link_rdev (mddev, rdev);
@@ -8592,7 +8592,7 @@ static void end_reshape(struct r5conf *conf)if (rdev->raid_disk >=0 && !test_bit (Journal, &rdev->flags) && !test_bit (In_sync, &rdev->flags)) - rdev->recovery_offset = MaxSector; +WRITE_ONCE (rdev->recovery_offset, MaxSector);spin_unlock_irq (&conf->device_lock);wake_up (&conf->wait_for_reshape);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 745/1376 tools/nolibc/powerpc: mark ctr and xer as clobbered by system call
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Weißschuh <[email protected]>
[ Upstream commit b9fc5a1742b0c8fb7edf066cc17fa0b18b7be623 ]
The system call can clobber the ctr and xer registers.
Make sure the compiler takes this into account.
The missing clobbers only seem to be an issue with newer compilers.
--- tools/include/nolibc/arch-powerpc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/include/nolibc/arch-powerpc.h +1 -1
@@ -23,7 +23,7 @@*/ #define _NOLIBC_SYSCALL_CLOBBERLIST \ - "memory", "cr0", "r12", "r11", "r10", "r9" + "memory", "cr0", "ctr", "xer", "r12", "r11", "r10", "r9"#define my_syscall0 (num) \ ({ \
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 746/1376 md: recheck spare changes before starting sync
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abd-Alrhman Masalkhi <[email protected]>
[ Upstream commit c7d34d17ea43ebc86b45d439ebb435e11ca44bca ]
remove_spares() and remove_and_add_spares() modify the array's rdev configuration. These operations are only safe after the array has been suspended.
md_start_sync() checks whether spare configuration changes are needed before taking reconfig_mutex. However, the rdev state can change before the mutex is acquired, so the initial check can become stale. In that case, md_choose_sync_action() may remove or replace rdevs while normal I/O is still accessing them.
The race can occur as follows:
raid10d Worker Normal IO ____________ _______________________ ______________________
raid10_write_request()
wait_blocked_dev()set Blocked
set Faulty
Skip Faulty rdev rrdev->nr_pending++ .repl_bio = bio
removeable_rdev = false .
array not suspended .
lock mddev goto err_handle
lock mddev (wait)
.
update sb .
clear Blocked .
.
unlock mddev .
lock mddev (acquires)
remove_spares()
removeable_rdev = true
raid10_remove_disk()
rdev = replacement
replacement = NULL
rdev_dec_pending(NULL)
unlock mddev (NULL)->nr_pending--
In this case, rdev_dec_pending() is called with a NULL pointer, resulting in a NULL pointer dereference when attempting to decrement nr_pending.
Fix this by suspending the array when spare configuration changes are needed, including for non-read-write arrays, and checking again after taking reconfig_mutex. If the array was not already suspended and a change is now needed, release the mutex, suspend the array, and reacquire the mutex before continuing.
--- drivers/md/md.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
drivers/md/md.c +13 -1
@@ -9583,13 +9583,25 @@ static void md_start_sync(struct work_struct *ws)* If reshape is still in progress, spares won't be added or removed * from conf until reshape is done. */ -if (mddev->reshape_position == MaxSector && +if ((mddev->reshape_position == MaxSector || !md_is_rdwr (mddev)) &&md_spares_need_change (mddev)) { suspend = true;mddev_suspend (mddev, false); }mddev_lock_nointr (mddev); + +/* +* The spare configuration can change before reconfig_mutex is acquired. +* Recheck while holding the lock and suspend if needed. +*/ +if (!suspend && (mddev->reshape_position == MaxSector || !md_is_rdwr (mddev)) && +md_spares_need_change (mddev)) { +mddev_unlock (mddev); +mddev_suspend_and_lock_nointr (mddev); + suspend = true; + } +if (!md_is_rdwr (mddev)) {/* * On a read-only array we can:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 747/1376 selftests/zram: fix kernel_gte() for POSIX sh
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cheng-Han Wu <[email protected]>
[ Upstream commit 649ba27dfac784427a01f9c95c09ecbcb88900d8 ]
Commit fc4eb486a59d ("selftests/zram: Skip max_comp_streams interface on newer kernel") added kernel_gte() to zram_lib.sh. The function uses the bash-specific [[ ... ]] conditional, but zram selftests source this file while running under /bin/sh.
On systems where /bin/sh is dash, such as Debian, the following test fails:
dash -c '
kernel_major=6; kernel_minor=1; major=6; minor=0
if [ $kernel_major -gt $major ]; then
echo ok
elif [[ $kernel_major -eq $major && $kernel_minor -ge $minor ]]; then
echo ok
fi'with:
dash: 5: [[: not found
Use separate POSIX test expressions joined by && instead.
--- tools/testing/selftests/zram/zram_lib.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/testing/selftests/zram/zram_lib.sh +1 -1
@@ -37,7 +37,7 @@ kernel_gte() if [ $kernel_major -gt $major ]; then return 0 - elif [[ $kernel_major -eq $major && $kernel_minor -ge $minor ]]; then + elif [ $kernel_major -eq $major ] && [ $kernel_minor -ge $minor ]; then return 0 fi
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 748/1376 slab: simplify init_kmem_cache_nodes() error handling
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vlastimil Babka <[email protected]>
[ Upstream commit 9d4e6ab865c48c70e684b176d3ee1574d092626f ]
We don't need to call free_kmem_cache_nodes() immediately when failing to allocate a kmem_cache_node, because when we return 0, do_kmem_cache_create() calls __kmem_cache_release() which also performs free_kmem_cache_nodes().
Stable-dep-of: 4c6eb712a91f ("wifi: ath12k: fix stride mismatch in mac_phy_caps_parse()")
--- mm/slub.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
mm/slub.c +1 -3
@@ -5323,10 +5323,8 @@ static int init_kmem_cache_nodes(struct kmem_cache *s) n =kmem_cache_alloc_node (kmem_cache_node,GFP_KERNEL , node); -if (!n) { -free_kmem_cache_nodes (s); +if (!n)return 0 ; - }init_kmem_cache_node (n); s->node[node] = n;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 749/1376 slab: Make slub local_(try)lock more precise for LOCKDEP
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexei Starovoitov <[email protected]>
[ Upstream commit 83382af9ddc3cb0ef43f67d049b461720ad785e6 ]
kmalloc_nolock() can be called from any context
the ___slab_alloc() can acquire local_trylock_t (which is rt_spin_lock in PREEMPT_RT) and attempt to acquire a different local_trylock_t while in the same task context.
The calling sequence might look like:kmalloc() -> tracepoint -> bpf -> kmalloc_nolock()
or more precisely:
__lock_acquire+0x12ad/0x2590 lock_acquire+0x133/0x2d0 rt_spin_lock+0x6f/0x250 ___slab_alloc+0xb7/0xec0 kmalloc_nolock_noprof+0x15a/0x430 my_debug_callback+0x20e/0x390 [testmod] ___slab_alloc+0x256/0xec0 __kmalloc_cache_noprof+0xd6/0x3b0
Make LOCKDEP understand that local_trylock_t-s protect different kmem_caches. In order to do that add lock_class_key for each kmem_cache and use that key in local_trylock_t.
This stack trace is possible on both PREEMPT_RT and !PREEMPT_RT, but teach lockdep about it only for PREEMPT_RT, since in !PREEMPT_RT the ___slab_alloc() code is using local_trylock_irqsave() when lockdep is on.
Note, this patch applies this logic to local_lock_t while the next one converts it to local_trylock_t. Both are mapped to rt_spin_lock in PREEMPT_RT.
Stable-dep-of: 4c6eb712a91f ("wifi: ath12k: fix stride mismatch in mac_phy_caps_parse()")
--- mm/slab.h | 1 + mm/slub.c | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+)
mm/slab.h +1 -0
@@ -258,6 +258,7 @@ struct kmem_cache_order_objects {struct kmem_cache {#ifndef CONFIG_SLUB_TINY struct kmem_cache_cpu __percpu *cpu_slab; +struct lock_class_key lock_key;#endif /* Used for retrieving partial slabs, etc. */ slab_flags_t flags;
mm/slub.c +20 -0
@@ -3078,12 +3078,29 @@ static inline void note_cmpxchg_failure(const char *n,static void init_kmem_cache_cpus (struct kmem_cache *s) { +#ifdef CONFIG_PREEMPT_RT +/* +* Register lockdep key for non-boot kmem caches to avoid +* WARN_ON_ONCE(static_obj(key))) in lockdep_register_key() +*/ +bool finegrain_lockdep = !init_section_contains (s,1 ); +#else +/* +* Don't bother with different lockdep classes for each +* kmem_cache, since we only use local_trylock_irqsave(). +*/ +bool finegrain_lockdep = false; +#endif int cpu;struct kmem_cache_cpu *c; +if (finegrain_lockdep) +lockdep_register_key (&s->lock_key);for_each_possible_cpu (cpu) { c =per_cpu_ptr (s->cpu_slab, cpu);local_lock_init (&c->lock); +if (finegrain_lockdep) +lockdep_set_class (&c->lock, &s->lock_key); c->tid =init_tid (cpu); } }
@@ -5304,6 +5321,9 @@ void __kmem_cache_release(struct kmem_cache *s) {cache_random_seq_destroy (s);#ifndef CONFIG_SLUB_TINY +#ifdef CONFIG_PREEMPT_RT +lockdep_unregister_key (&s->lock_key); +#endif free_percpu (s->cpu_slab);#endif free_kmem_cache_nodes (s);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 750/1376 slab: Reuse first bit for OBJEXTS_ALLOC_FAIL
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexei Starovoitov <[email protected]>
[ Upstream commit 7612833192d56af86061de8ab51989b75daf5b0d ]
Since the combination of valid upper bits in slab->obj_exts with OBJEXTS_ALLOC_FAIL bit can never happen,
use OBJEXTS_ALLOC_FAIL == (1ull << 0) as a magic sentinel instead of (1ull << 2) to free up bit 2.
Stable-dep-of: 4c6eb712a91f ("wifi: ath12k: fix stride mismatch in mac_phy_caps_parse()")
--- include/linux/memcontrol.h | 10 ++++++++-- mm/slub.c | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-)
include/linux/memcontrol.h +8 -2
@@ -344,17 +344,23 @@ enum page_memcg_data_flags { __NR_MEMCG_DATA_FLAGS = (1UL << 2), }; +#define __OBJEXTS_ALLOC_FAIL MEMCG_DATA_OBJEXTS#define __FIRST_OBJEXT_FLAG __NR_MEMCG_DATA_FLAGS#else /* CONFIG_MEMCG */ +#define __OBJEXTS_ALLOC_FAIL (1UL << 0)#define __FIRST_OBJEXT_FLAG (1UL << 0)#endif /* CONFIG_MEMCG */ enum objext_flags { -/* slabobj_ext vector failed to allocate */ -OBJEXTS_ALLOC_FAIL = __FIRST_OBJEXT_FLAG, +/* +* Use bit 0 with zero other bits to signal that slabobj_ext vector +* failed to allocate. The same bit 0 with valid upper bits means +* MEMCG_DATA_OBJEXTS. +*/ +OBJEXTS_ALLOC_FAIL = __OBJEXTS_ALLOC_FAIL,/* the next bit after the last actual flag */ __NR_OBJEXTS_FLAGS = (__FIRST_OBJEXT_FLAG <<1 ), };
mm/slub.c +1 -1
@@ -1958,7 +1958,7 @@ static inline void handle_failed_objexts_alloc(unsigned long obj_exts,* objects with no tag reference. Mark all references in this * vector as empty to avoid warnings later on. */ -if (obj_exts &OBJEXTS_ALLOC_FAIL ) { +if (obj_exts ==OBJEXTS_ALLOC_FAIL ) {unsigned int i;for (i =0 ; i < objects; i++)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 751/1376 wifi: ath12k: fix stride mismatch in mac_phy_caps_parse()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Johnson <[email protected]>
[ Upstream commit 4c6eb712a91fa079be6f9f1419c96e0ad2227081 ]
Currently, in ath12k_wmi_mac_phy_caps_parse(), kzalloc() sizes the mac_phy_caps buffer as tot_phy_id * len, where len is clamped to min(firmware_len, sizeof(struct ath12k_wmi_mac_phy_caps_params)). The subsequent memcpy() destination advances by sizeof(full struct) per slot via C pointer arithmetic, not by the clamped len. When firmware sends short TLVs, the second and later slots are written past the end of the allocation.
The reader in ath12k_pull_mac_phy_cap_svc_ready_ext() also indexes the buffer with full-struct pointer arithmetic, so the allocation must match that stride.
Fix by using kzalloc_objs(), which derives the element size from the pointer type, making allocation size and pointer stride provably consistent regardless of what len the firmware provides.
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c7-00108-QCAHMTSWPL_V1.0_V2.0_SILICONZ_UPSTREAM-3
--- drivers/net/wireless/ath/ath12k/wmi.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/net/wireless/ath/ath12k/wmi.c +5 -3
@@ -4073,14 +4073,16 @@ static int ath12k_wmi_mac_phy_caps_parse(struct ath12k_base *soc,if (svc_rdy_ext->n_mac_phy_caps >= svc_rdy_ext->tot_phy_id)return -ENOBUFS ; - len =min_t (u16, len,sizeof (struct ath12k_wmi_mac_phy_caps_params ));if (!svc_rdy_ext->n_mac_phy_caps) { - svc_rdy_ext->mac_phy_caps =kzalloc ((svc_rdy_ext->tot_phy_id) * len, -GFP_ATOMIC ); + svc_rdy_ext->mac_phy_caps = +kzalloc_objs (*svc_rdy_ext->mac_phy_caps, + svc_rdy_ext->tot_phy_id, +GFP_ATOMIC );if (!svc_rdy_ext->mac_phy_caps)return -ENOMEM ; } + len =min_t (u16, len,sizeof (struct ath12k_wmi_mac_phy_caps_params ));memcpy (svc_rdy_ext->mac_phy_caps + svc_rdy_ext->n_mac_phy_caps, ptr, len); svc_rdy_ext->n_mac_phy_caps++;return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 752/1376 wifi: ath11k: fix stride mismatch in mac_phy_caps_parse()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Johnson <[email protected]>
[ Upstream commit 7a246c72132eb943b5844ba79dad597b47429dba ]
Currently, in ath11k_wmi_tlv_mac_phy_caps_parse(), kcalloc() sizes the mac_phy_caps buffer as tot_phy_id * len, where len is clamped to min(firmware_len, sizeof(struct wmi_mac_phy_capabilities)). The subsequent memcpy() destination advances by sizeof(full struct) per slot via C pointer arithmetic, not by the clamped len. When firmware sends short TLVs, the second and later slots are written past the end of the allocation.
The reader in ath11k_pull_mac_phy_cap_svc_ready_ext() also indexes the buffer with full-struct pointer arithmetic, so the allocation must match that stride.
Fix by using kzalloc_objs(), which derives the element size from the pointer type, making allocation size and pointer stride provably consistent regardless of what len the firmware provides.
Compile tested only.
--- drivers/net/wireless/ath/ath11k/wmi.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/net/wireless/ath/ath11k/wmi.c +5 -3
@@ -4756,14 +4756,16 @@ static int ath11k_wmi_tlv_mac_phy_caps_parse(struct ath11k_base *soc,if (svc_rdy_ext->n_mac_phy_caps >= svc_rdy_ext->tot_phy_id)return -ENOBUFS ; - len =min_t (u16, len,sizeof (struct wmi_mac_phy_capabilities ));if (!svc_rdy_ext->n_mac_phy_caps) { - svc_rdy_ext->mac_phy_caps =kcalloc (svc_rdy_ext->tot_phy_id, - len,GFP_ATOMIC ); + svc_rdy_ext->mac_phy_caps = +kzalloc_objs (*svc_rdy_ext->mac_phy_caps, + svc_rdy_ext->tot_phy_id, +GFP_ATOMIC );if (!svc_rdy_ext->mac_phy_caps)return -ENOMEM ; } + len =min_t (u16, len,sizeof (struct wmi_mac_phy_capabilities ));memcpy (svc_rdy_ext->mac_phy_caps + svc_rdy_ext->n_mac_phy_caps, ptr, len); svc_rdy_ext->n_mac_phy_caps++;return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 753/1376 rcu: Mark accesses to ->rcu_urgent_qs and ->rcu_need_heavy_qs
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Itai Handler <[email protected]>
[ Upstream commit 27d73e81195b395270117ff77c47be2ed9b09b12 ]
rcu_all_qs() and rcu_note_context_switch() read/clear the per-CPU ->rcu_urgent_qs and ->rcu_need_heavy_qs flags with plain raw_cpu_read() and this_cpu_write(), while the RCU core clears them with WRITE_ONCE() in rcu_disable_urgency_upon_qs(). KCSAN flags the resulting same-CPU race:
BUG: KCSAN: data-race in rcu_all_qs / rcu_disable_urgency_upon_qs
It is benign -- the flags are advisory and rcu_all_qs() re-reads ->rcu_urgent_qs with smp_load_acquire() before acting on it -- but these are the last unmarked accesses to the two flags; every other access already uses READ_ONCE()/WRITE_ONCE()/smp_*. Mark them to match. No functional change.
Reproduced on a PREEMPT_NONE, CONFIG_KCSAN_INTERRUPT_WATCHER=y kernel with a pthreads program whose threads (two per CPU) loop reading a large file:
for (;;) {
int fd = open("/proc/kallsyms", O_RDONLY);
while (read(fd, buf, sizeof(buf)) > 0)
;
close(fd);
}The read()s drive cond_resched() -> rcu_all_qs() while the busy CPUs keep the grace period urgent, so the RCU core clears the flags concurrently.
--- kernel/rcu/tree_plugin.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
kernel/rcu/tree_plugin.h +5 -5
@@ -973,7 +973,7 @@ void rcu_all_qs(void) {unsigned long flags; -if (!raw_cpu_read (rcu_data.rcu_urgent_qs)) +if (!READ_ONCE (*raw_cpu_ptr (&rcu_data.rcu_urgent_qs)))return ;preempt_disable ();// For CONFIG_PREEMPT_COUNT=y kernels /* Load rcu_urgent_qs before other flags. */
@@ -981,8 +981,8 @@ void rcu_all_qs(void)preempt_enable ();return ; } -this_cpu_write (rcu_data.rcu_urgent_qs, false); -if (unlikely (raw_cpu_read (rcu_data.rcu_need_heavy_qs))) { +WRITE_ONCE (*this_cpu_ptr (&rcu_data.rcu_urgent_qs), false); +if (unlikely (READ_ONCE (*this_cpu_ptr (&rcu_data.rcu_need_heavy_qs)))) {local_irq_save (flags);rcu_momentary_eqs ();local_irq_restore (flags);
@@ -1002,8 +1002,8 @@ void rcu_note_context_switch(bool preempt)/* Load rcu_urgent_qs before other flags. */ if (!smp_load_acquire (this_cpu_ptr (&rcu_data.rcu_urgent_qs))) goto out; -this_cpu_write (rcu_data.rcu_urgent_qs, false); -if (unlikely (raw_cpu_read (rcu_data.rcu_need_heavy_qs))) +WRITE_ONCE (*this_cpu_ptr (&rcu_data.rcu_urgent_qs), false); +if (unlikely (READ_ONCE (*this_cpu_ptr (&rcu_data.rcu_need_heavy_qs))))rcu_momentary_eqs (); out:rcu_tasks_qs (current, preempt);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 754/1376 arm64: dts: qcom: msm8998: Dont pull-up I2C pins by default in sleep
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Konrad Dybcio <[email protected]>
[ Upstream commit 58ce9a2b9099bb26aed55d4e350c32af94930532 ]
When the I2C controller is disabled, no communication is expected to take place. Without traffic on the bus, the pull-up is unnecessary.
Both the vendor kernel for this platform and DTs of other SoCs in upstream concur this logic. Change the default and clean up now-NOP overrides.
--- .../dts/qcom/msm8998-sony-xperia-yoshino.dtsi | 4 ---- .../boot/dts/qcom/msm8998-xiaomi-sagit.dts | 5 ---- arch/arm64/boot/dts/qcom/msm8998.dtsi | 24 +++++++++---------- 3 files changed, 12 insertions(+), 21 deletions(-)
arch/arm64/boot/dts/qcom/msm8998-sony-xperia-yoshino.dtsi +0 -4
@@ -229,10 +229,6 @@ rmi4-f11@11 { }; }; -&blsp1_i2c5_sleep { - bias-disable; -}; - &blsp1_uart3 { status = "okay";
arch/arm64/boot/dts/qcom/msm8998-xiaomi-sagit.dts +0 -5
@@ -217,11 +217,6 @@ rmi4-f1a@1a { }; }; -&blsp1_i2c5_sleep { - /delete-property/ bias-pull-up; - bias-disable; -}; - &blsp1_uart3 { status = "okay";
arch/arm64/boot/dts/qcom/msm8998.dtsi +12 -12
@@ -1166,7 +1166,7 @@ blsp1_i2c1_sleep: blsp1-i2c1-sleep-state-state { pins = "gpio2", "gpio3"; function = "blsp_i2c1"; drive-strength = <2>; - bias-pull-up; + bias-disable; }; blsp1_i2c2_default: blsp1-i2c2-default-state {
@@ -1180,7 +1180,7 @@ blsp1_i2c2_sleep: blsp1-i2c2-sleep-state-state { pins = "gpio32", "gpio33"; function = "blsp_i2c2"; drive-strength = <2>; - bias-pull-up; + bias-disable; }; blsp1_i2c3_default: blsp1-i2c3-default-state {
@@ -1194,7 +1194,7 @@ blsp1_i2c3_sleep: blsp1-i2c3-sleep-state { pins = "gpio47", "gpio48"; function = "blsp_i2c3"; drive-strength = <2>; - bias-pull-up; + bias-disable; }; blsp1_i2c4_default: blsp1-i2c4-default-state {
@@ -1208,7 +1208,7 @@ blsp1_i2c4_sleep: blsp1-i2c4-sleep-state { pins = "gpio10", "gpio11"; function = "blsp_i2c4"; drive-strength = <2>; - bias-pull-up; + bias-disable; }; blsp1_i2c5_default: blsp1-i2c5-default-state {
@@ -1222,7 +1222,7 @@ blsp1_i2c5_sleep: blsp1-i2c5-sleep-state { pins = "gpio87", "gpio88"; function = "blsp_i2c5"; drive-strength = <2>; - bias-pull-up; + bias-disable; }; blsp1_i2c6_default: blsp1-i2c6-default-state {
@@ -1236,7 +1236,7 @@ blsp1_i2c6_sleep: blsp1-i2c6-sleep-state { pins = "gpio43", "gpio44"; function = "blsp_i2c6"; drive-strength = <2>; - bias-pull-up; + bias-disable; }; blsp1_spi_b_default: blsp1-spi-b-default-state {
@@ -1301,7 +1301,7 @@ blsp2_i2c1_sleep: blsp2-i2c1-sleep-state { pins = "gpio55", "gpio56"; function = "blsp_i2c7"; drive-strength = <2>; - bias-pull-up; + bias-disable; }; blsp2_i2c2_default: blsp2-i2c2-default-state {
@@ -1315,7 +1315,7 @@ blsp2_i2c2_sleep: blsp2-i2c2-sleep-state { pins = "gpio6", "gpio7"; function = "blsp_i2c8"; drive-strength = <2>; - bias-pull-up; + bias-disable; }; blsp2_i2c3_default: blsp2-i2c3-default-state {
@@ -1329,7 +1329,7 @@ blsp2_i2c3_sleep: blsp2-i2c3-sleep-state { pins = "gpio51", "gpio52"; function = "blsp_i2c9"; drive-strength = <2>; - bias-pull-up; + bias-disable; }; blsp2_i2c4_default: blsp2-i2c4-default-state {
@@ -1343,7 +1343,7 @@ blsp2_i2c4_sleep: blsp2-i2c4-sleep-state { pins = "gpio67", "gpio68"; function = "blsp_i2c10"; drive-strength = <2>; - bias-pull-up; + bias-disable; }; blsp2_i2c5_default: blsp2-i2c5-default-state {
@@ -1357,7 +1357,7 @@ blsp2_i2c5_sleep: blsp2-i2c5-sleep-state { pins = "gpio60", "gpio61"; function = "blsp_i2c11"; drive-strength = <2>; - bias-pull-up; + bias-disable; }; blsp2_i2c6_default: blsp2-i2c6-default-state {
@@ -1371,7 +1371,7 @@ blsp2_i2c6_sleep: blsp2-i2c6-sleep-state { pins = "gpio83", "gpio84"; function = "blsp_i2c12"; drive-strength = <2>; - bias-pull-up; + bias-disable; }; blsp2_spi1_default: blsp2-spi1-default-state {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 755/1376 arm64: dts: qcom: sdm632-motorola-ocean: Fix LED default trigger property
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Konrad Dybcio <[email protected]>
[ Upstream commit c82ea31fb783d9ce4080eca1a7bb855f4648fc28 ]
The correct property name is "linux,default-trigger", not "default-trigger". Fix it to avoid DT checker warnings and let the OSes consume the intended information.
--- arch/arm64/boot/dts/qcom/sdm632-motorola-ocean.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm64/boot/dts/qcom/sdm632-motorola-ocean.dts +1 -1
@@ -130,7 +130,7 @@ led-controller@36 { led: led@1 { reg = <1>; - default-trigger = "backlight"; + linux,default-trigger = "backlight"; function = LED_FUNCTION_BACKLIGHT; led-sources = <0 1 2>; };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 756/1376 arm64: dts: qcom: qcs404: Fix DTBS Check errors in usb controller nodes
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Krishna Kurapati <[email protected]>
[ Upstream commit 9812d0a3077489f67afaca84dcc7e01a440ee106 ]
The following errors pop up when DTBS check is done for qcs404 based platforms:
arch/arm64/boot/dts/qcom/qcs404-evb-4000.dtb: usb@79b8800 (qcom,qcs404- dwc3): interrupt-names:1: 'qusb2_phy' was expected
from schema $id: http://devicetree.org/schemas/usb/qcom,dwc3.yaml
arch/arm64/boot/dts/qcom/qcs404-evb-4000.dtb: usb@79b8800 (qcom,qcs404- dwc3): interrupt-names:2: 'hs_phy_irq' was expected
from schema $id: http://devicetree.org/schemas/usb/qcom,dwc3.yaml
arch/arm64/boot/dts/qcom/qcs404-evb-4000.dtb: usb@7678800 (qcom,qcs404- dwc3): interrupt-names:2: 'hs_phy_irq' was expected
from schema $id: http://devicetree.org/schemas/usb/qcom,dwc3.yaml
arch/arm64/boot/dts/qcom/qcs404-evb-4000.dtb: usb@7678800 (qcom,qcs404- dwc3): interrupt-names:1: 'qusb2_phy' was expected
from schema $id: http://devicetree.org/schemas/usb/qcom,dwc3.yaml
Modify ordering of hs_phy and qusb2_phy interrupts to fix the errors.
--- arch/arm64/boot/dts/qcom/qcs404.dtsi | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
arch/arm64/boot/dts/qcom/qcs404.dtsi +8 -8
@@ -677,11 +677,11 @@ usb3: usb@7678800 { assigned-clock-rates = <19200000>, <200000000>; interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 319 IRQ_TYPE_LEVEL_HIGH>; + <GIC_SPI 319 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "pwr_event", - "hs_phy_irq", - "qusb2_phy"; + "qusb2_phy", + "hs_phy_irq"; status = "disabled";
@@ -714,11 +714,11 @@ usb2: usb@79b8800 { assigned-clock-rates = <19200000>, <133333333>; interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH>; + <GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "pwr_event", - "hs_phy_irq", - "qusb2_phy"; + "qusb2_phy", + "hs_phy_irq"; status = "disabled";
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 757/1376 clk: qcom: gcc-qcm2290: dont park QUP RCGs upon registration
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Baryshkov <[email protected]>
[ Upstream commit 9c4cee964e0ccc155e4ab8fa6cec88fffc262c63 ]
The gcc_qupv3_wrap0_s[0-5]_clk_src RCGs feed the QUP serial engines (UART/I2C/SPI). Since shared RCGs are parked to XO at registration time, binding the gcc-qcm2290 driver reprograms these clocks away from the rate configured by the bootloader. For the UART used as the boot console this drops early console output until the serial driver later reconfigures the clock.
Switch the QUP wrap0 clock sources over to clk_rcg2_shared_no_init_park_ops so their frequency is left unchanged at registration time, keeping the bootloader-configured console working across the gcc driver probe.
--- drivers/clk/qcom/gcc-qcm2290.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/clk/qcom/gcc-qcm2290.c +6 -6
@@ -1082,7 +1082,7 @@ static struct clk_init_data gcc_qupv3_wrap0_s0_clk_src_init = { .name = "gcc_qupv3_wrap0_s0_clk_src", .parent_data = gcc_parents_1, .num_parents = ARRAY_SIZE(gcc_parents_1), - .ops = &clk_rcg2_shared_ops, + .ops = &clk_rcg2_shared_no_init_park_ops, };static struct clk_rcg2 gcc_qupv3_wrap0_s0_clk_src = {
@@ -1098,7 +1098,7 @@ static struct clk_init_data gcc_qupv3_wrap0_s1_clk_src_init = { .name = "gcc_qupv3_wrap0_s1_clk_src", .parent_data = gcc_parents_1, .num_parents = ARRAY_SIZE(gcc_parents_1), - .ops = &clk_rcg2_shared_ops, + .ops = &clk_rcg2_shared_no_init_park_ops, };static struct clk_rcg2 gcc_qupv3_wrap0_s1_clk_src = {
@@ -1114,7 +1114,7 @@ static struct clk_init_data gcc_qupv3_wrap0_s2_clk_src_init = { .name = "gcc_qupv3_wrap0_s2_clk_src", .parent_data = gcc_parents_1, .num_parents = ARRAY_SIZE(gcc_parents_1), - .ops = &clk_rcg2_shared_ops, + .ops = &clk_rcg2_shared_no_init_park_ops, };static struct clk_rcg2 gcc_qupv3_wrap0_s2_clk_src = {
@@ -1130,7 +1130,7 @@ static struct clk_init_data gcc_qupv3_wrap0_s3_clk_src_init = { .name = "gcc_qupv3_wrap0_s3_clk_src", .parent_data = gcc_parents_1, .num_parents = ARRAY_SIZE(gcc_parents_1), - .ops = &clk_rcg2_shared_ops, + .ops = &clk_rcg2_shared_no_init_park_ops, };static struct clk_rcg2 gcc_qupv3_wrap0_s3_clk_src = {
@@ -1146,7 +1146,7 @@ static struct clk_init_data gcc_qupv3_wrap0_s4_clk_src_init = { .name = "gcc_qupv3_wrap0_s4_clk_src", .parent_data = gcc_parents_1, .num_parents = ARRAY_SIZE(gcc_parents_1), - .ops = &clk_rcg2_shared_ops, + .ops = &clk_rcg2_shared_no_init_park_ops, };static struct clk_rcg2 gcc_qupv3_wrap0_s4_clk_src = {
@@ -1162,7 +1162,7 @@ static struct clk_init_data gcc_qupv3_wrap0_s5_clk_src_init = { .name = "gcc_qupv3_wrap0_s5_clk_src", .parent_data = gcc_parents_1, .num_parents = ARRAY_SIZE(gcc_parents_1), - .ops = &clk_rcg2_shared_ops, + .ops = &clk_rcg2_shared_no_init_park_ops, };static struct clk_rcg2 gcc_qupv3_wrap0_s5_clk_src = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 758/1376 arm64: dts: qcom: sc8280xp-crd: Fix the pin index for misc_3p3_reg_en
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Konrad Dybcio <[email protected]>
[ Upstream commit 0e05c183f3b97427f00d619132ba5984494f6886 ]
The correct pin is GPIO1. Fix it.
--- arch/arm64/boot/dts/qcom/sc8280xp-crd.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/arm64/boot/dts/qcom/sc8280xp-crd.dts +2 -2
@@ -167,7 +167,7 @@ vreg_misc_3p3: regulator-misc-3p3 { regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; - gpio = <&pmc8280_1_gpios 2 GPIO_ACTIVE_HIGH>; + gpio = <&pmc8280_1_gpios 1 GPIO_ACTIVE_HIGH>; enable-active-high; pinctrl-names = "default";
@@ -759,7 +759,7 @@ edp_bl_reg_en: edp-bl-reg-en-state { }; misc_3p3_reg_en: misc-3p3-reg-en-state { - pins = "gpio2"; + pins = "gpio1"; function = "normal"; }; };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 759/1376 firmware: qcom_scm: Add API to get waitqueue IRQ info
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Unnathi Chalicheemala <[email protected]>
[ Upstream commit da9e6b1a96b1eef47542ec46b67e3f4f883fed3b ]
Bootloader and firmware for SM8650 and older chipsets expect node name as "qcom_scm", in order to patch the wait queue IRQ information. However, DeviceTree uses node name "scm" and this mismatch prevents firmware from correctly identifying waitqueue IRQ information. Waitqueue IRQ is used for signaling between secure and non-secure worlds.
To resolve this, introduce qcom_scm_get_waitq_irq() that'll get the hardware IRQ number to be used from firmware instead of relying on data provided by devicetree, thereby bypassing the DeviceTree node name mismatch.
This hardware IRQ number is converted to a Linux IRQ number using newly qcom_scm_fill_irq_fwspec_params(). This Linux IRQ number is then supplied to the threaded_irq call.
Stable-dep-of: 966d23c7e68e ("firmware: qcom: scm: Fix NULL dereference in IRQ handler before __scm is published")
--- drivers/firmware/qcom/qcom_scm.c | 62 +++++++++++++++++++++++++++++++- drivers/firmware/qcom/qcom_scm.h | 1 + 2 files changed, 62 insertions(+), 1 deletion(-)
drivers/firmware/qcom/qcom_scm.c +61 -1
@@ -30,11 +30,18 @@#include <linux/sizes.h> #include <linux/types.h> +#include <dt-bindings/interrupt-controller/arm-gic.h> +#include "qcom_scm.h" #include "qcom_tzmem.h" static u32 download_mode; +#define GIC_SPI_BASE 32 +#define GIC_MAX_SPI 1019 // SPIs in GICv3 spec range from 32..1019 +#define GIC_ESPI_BASE 4096 +#define GIC_MAX_ESPI 5119 // ESPIs in GICv3 spec range from 4096..5119 +struct qcom_scm {struct device *dev;struct clk *core_clk;
@@ -1847,6 +1854,56 @@ bool qcom_scm_is_available(void) }EXPORT_SYMBOL_GPL (qcom_scm_is_available); +static int qcom_scm_fill_irq_fwspec_params (struct irq_fwspec *fwspec,u32 hwirq) +{ +if (hwirq >=GIC_SPI_BASE && hwirq <=GIC_MAX_SPI ) { + fwspec->param[0 ] =GIC_SPI ; + fwspec->param[1 ] = hwirq -GIC_SPI_BASE ; + }else if (hwirq >=GIC_ESPI_BASE && hwirq <=GIC_MAX_ESPI ) { + fwspec->param[0 ] =GIC_ESPI ; + fwspec->param[1 ] = hwirq -GIC_ESPI_BASE ; + }else { +WARN (1 ,"Unexpected hwirq: %d\n" , hwirq); +return -ENXIO ; + } + + fwspec->param[2 ] =IRQ_TYPE_EDGE_RISING ; + fwspec->param_count =3 ; + +return 0 ; +} + +static int qcom_scm_get_waitq_irq (struct qcom_scm *scm) +{ +struct qcom_scm_desc desc = { + .svc =QCOM_SCM_SVC_WAITQ , + .cmd =QCOM_SCM_WAITQ_GET_INFO , + .owner =ARM_SMCCC_OWNER_SIP + }; +struct device_node *parent_irq_node; +struct irq_fwspec fwspec; +struct qcom_scm_res res; +u32 hwirq; +int ret; + + ret =qcom_scm_call_atomic (scm->dev, &desc, &res); +if (ret) +return ret; + + hwirq = res.result[1 ] &GENMASK (15 ,0 ); + ret =qcom_scm_fill_irq_fwspec_params (&fwspec, hwirq); +if (ret) +return ret; + + parent_irq_node =of_irq_find_parent (scm->dev->of_node); +if (!parent_irq_node) +return -ENODEV ; + + fwspec.fwnode =of_fwnode_handle (parent_irq_node); + +return irq_create_fwspec_mapping (&fwspec); +} +static int qcom_scm_assert_valid_wq_ctx (u32 wq_ctx) {/* FW currently only supports a single wq_ctx (zero).
@@ -2003,7 +2060,10 @@ static int qcom_scm_probe(struct platform_device *pdev)/* Paired with smp_load_acquire() in qcom_scm_is_available(). */ smp_store_release (&__scm, scm); - irq =platform_get_irq_optional (pdev,0 ); + irq =qcom_scm_get_waitq_irq (scm); +if (irq <0 ) + irq =platform_get_irq_optional (pdev,0 ); +if (irq <0 ) {if (irq != -ENXIO ) { ret = irq;
drivers/firmware/qcom/qcom_scm.h +1 -0
@@ -143,6 +143,7 @@ struct qcom_tzmem_pool *qcom_scm_get_tzmem_pool(void);#define QCOM_SCM_SVC_WAITQ 0x24#define QCOM_SCM_WAITQ_RESUME 0x02#define QCOM_SCM_WAITQ_GET_WQ_CTX 0x03 +#define QCOM_SCM_WAITQ_GET_INFO 0x04#define QCOM_SCM_SVC_GPU 0x28#define QCOM_SCM_SVC_GPU_INIT_REGS 0x01
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 760/1376 firmware: qcom_scm: Support multiple waitq contexts
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Unnathi Chalicheemala <[email protected]>
[ Upstream commit ccd207ec848e768da41465352a0f52081eec6bb1 ]
Currently, only a single waitqueue context exists in the driver. Multi-waitqueue mechanism is added in firmware to support the case, when multiple VMs make SMC calls or single VM making multiple calls on same CPU. Enhance the driver to support multiple waitqueue when support is present in the firmware.
When VMs make a SMC call, firmware allocates a waitqueue context, assuming the SMC call to be a blocking call. The SMC calls that cannot acquire resources, while execution in firmware, are returned to sleep in the calling VM. When the resource becomes available in the firmware, the VM gets notified to wake the sleeping thread and resume SMC call. The current qcom_scm driver supports single waitqueue as the old firmwares support only single waitqueue with waitqueue id zero. Multi-waitqueue mechanism is added in firmware starting SM8650 to support the case when multiple VMs make SMC calls or single VM making multiple calls on same CPU. To enable this support in qcom_scm driver, add support for handling multiple waitqueues. For instance, SM8650 firmware can allocate two such waitq contexts, so the driver needs to implement two waitqueue contexts. For a generalized approach, the number of supported waitqueues can be queried from the firmware using a SMC call.
Introduce qcom_scm_query_waitq_count to get the number of waitqueue contexts supported by the firmware and allocate “N” unique waitqueue contexts with a dynamic sized array where each unique wq_ctx is associated with a struct completion variable for easy lookup. Older targets which support only a single waitqueue, may return an error for qcom_scm_query_waitq_count, set the wq_cnt to one for such failures.
Stable-dep-of: 966d23c7e68e ("firmware: qcom: scm: Fix NULL dereference in IRQ handler before __scm is published")
--- drivers/firmware/qcom/qcom_scm.c | 72 ++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 22 deletions(-)
drivers/firmware/qcom/qcom_scm.c +50 -22
@@ -48,7 +48,7 @@ struct qcom_scm {struct clk *iface_clk;struct clk *bus_clk;struct icc_path *path; -struct completion waitq_comp; +struct completion *waitq_comps;struct reset_controller_dev reset;/* control access to the interconnect path */
@@ -58,6 +58,7 @@ struct qcom_scm {u64 dload_mode_addr;struct qcom_tzmem_pool *mempool; +unsigned int wq_cnt; };struct qcom_scm_current_perm_info {
@@ -137,6 +138,8 @@ static const u8 qcom_scm_cpu_warm_bits[QCOM_SCM_BOOT_MAX_CPUS] = {#define QCOM_DLOAD_MINIDUMP 2#define QCOM_DLOAD_BOTHDUMP 3 +#define QCOM_SCM_DEFAULT_WAITQ_COUNT 1 +static const char *const qcom_scm_convention_names[] = { [SMC_CONVENTION_UNKNOWN ] ="unknown" , [SMC_CONVENTION_ARM_32 ] ="smc arm 32" ,
@@ -1873,6 +1876,23 @@ static int qcom_scm_fill_irq_fwspec_params(struct irq_fwspec *fwspec, u32 hwirq)return 0 ; } +static int qcom_scm_query_waitq_count (struct qcom_scm *scm) +{ +struct qcom_scm_desc desc = { + .svc =QCOM_SCM_SVC_WAITQ , + .cmd =QCOM_SCM_WAITQ_GET_INFO , + .owner =ARM_SMCCC_OWNER_SIP + }; +struct qcom_scm_res res; +int ret; + + ret =qcom_scm_call_atomic (scm->dev, &desc, &res); +if (ret) +return ret; + +return res.result[0 ] &GENMASK (7 ,0 ); +} +static int qcom_scm_get_waitq_irq (struct qcom_scm *scm) {struct qcom_scm_desc desc = {
@@ -1904,42 +1924,40 @@ static int qcom_scm_get_waitq_irq(struct qcom_scm *scm)return irq_create_fwspec_mapping (&fwspec); } -static int qcom_scm_assert_valid_wq_ctx (u32 wq_ctx) +static struct completion *qcom_scm_get_completion (u32 wq_ctx) { -/* FW currently only supports a single wq_ctx (zero). -* TODO: Update this logic to include dynamic allocation and lookup of -* completion structs when FW supports more wq_ctx values. -*/ -if (wq_ctx !=0 ) { -dev_err (__scm->dev,"Firmware unexpectedly passed non-zero wq_ctx\n" ); -return -EINVAL ; - } +struct completion *wq; -return 0 ; +if (WARN_ON_ONCE (wq_ctx >= __scm->wq_cnt)) +return ERR_PTR (-EINVAL ); + + wq = &__scm->waitq_comps[wq_ctx]; + +return wq; }int qcom_scm_wait_for_wq_completion (u32 wq_ctx) { -int ret; +struct completion *wq; - ret =qcom_scm_assert_valid_wq_ctx (wq_ctx); -if (ret) -return ret; + wq =qcom_scm_get_completion (wq_ctx); +if (IS_ERR (wq)) +return PTR_ERR (wq); -wait_for_completion (&__scm->waitq_comp); +wait_for_completion (wq);return 0 ; }static int qcom_scm_waitq_wakeup (unsigned int wq_ctx) { -int ret; +struct completion *wq; - ret =qcom_scm_assert_valid_wq_ctx (wq_ctx); -if (ret) -return ret; + wq =qcom_scm_get_completion (wq_ctx); +if (IS_ERR (wq)) +return PTR_ERR (wq); -complete (&__scm->waitq_comp); +complete (wq);return 0 ; }
@@ -2015,6 +2033,7 @@ static int qcom_scm_probe(struct platform_device *pdev)struct qcom_tzmem_pool_config pool_config;struct qcom_scm *scm;int irq, ret; +int i; scm =devm_kzalloc (&pdev->dev,sizeof (*scm),GFP_KERNEL );if (!scm)
@@ -2025,7 +2044,6 @@ static int qcom_scm_probe(struct platform_device *pdev)if (ret <0 )return ret; -init_completion (&scm->waitq_comp);mutex_init (&scm->scm_bw_lock); scm->path =devm_of_icc_get (&pdev->dev,NULL );
@@ -2060,6 +2078,16 @@ static int qcom_scm_probe(struct platform_device *pdev)/* Paired with smp_load_acquire() in qcom_scm_is_available(). */ smp_store_release (&__scm, scm); + ret =qcom_scm_query_waitq_count (scm); + scm->wq_cnt = ret <0 ?QCOM_SCM_DEFAULT_WAITQ_COUNT : ret; + scm->waitq_comps =devm_kcalloc (&pdev->dev, scm->wq_cnt,sizeof (*scm->waitq_comps), +GFP_KERNEL ); +if (!scm->waitq_comps) +return -ENOMEM ; + +for (i =0 ; i < scm->wq_cnt; i++) +init_completion (&scm->waitq_comps[i]); + irq =qcom_scm_get_waitq_irq (scm);if (irq <0 ) irq =platform_get_irq_optional (pdev,0 );
Signature · 1 line
2.53.0
Re: [PATCH 6.12 0760/1376] firmware: qcom_scm: Support multiple waitq contexts
Quoted 37 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Unnathi Chalicheemala <[email protected]>
[ Upstream commit
ccd207ec848e768da41465352a0f52081eec6bb1]Currently, only a single waitqueue context exists in the driver. Multi-waitqueue mechanism is added in firmware to support the case, when multiple VMs make SMC calls or single VM making multiple calls on same CPU. Enhance the driver to support multiple waitqueue when support is present in the firmware.
When VMs make a SMC call, firmware allocates a waitqueue context, assuming the SMC call to be a blocking call. The SMC calls that cannot acquire resources, while execution in firmware, are returned to sleep in the calling VM. When the resource becomes available in the firmware, the VM gets notified to wake the sleeping thread and resume SMC call. The current
qcom_scmdriver supports single waitqueue as the old firmwares support only single waitqueue with waitqueue id zero. Multi-waitqueue mechanism is added in firmware starting SM8650 to support the case when multiple VMs make SMC calls or single VM making multiple calls on same CPU. To enable this support inqcom_scmdriver, add support for handling multiple waitqueues. For instance, SM8650 firmware can allocate two such waitq contexts, so the driver needs to implement two waitqueue contexts. For a generalized approach, the number of supported waitqueues can be queried from the firmware using a SMC call.Introduce
qcom_scm_query_waitq_countto get the number of waitqueue contexts supported by the firmware and allocate “N” unique waitqueue contexts with a dynamic sized array where each uniquewq_ctxis associated with a struct completion variable for easy lookup. Older targets which support only a single waitqueue, may return an error forqcom_scm_query_waitq_count, set thewq_cntto one for such failures.
Quoted 8 lines
Reviewed-by Bartosz Golaszewski <[email protected]>Signed-off-by Unnathi Chalicheemala <[email protected]>Signed-off-by Shivendra Pratap <[email protected]>Reviewed-by Mukesh Ojha <[email protected]>Signed-off-by Bjorn Andersson <[email protected]>Stable-dep-of:
966d23c7e68e("firmware: qcom: scm: Fix NULL dereference in IRQ handler before__scmis published")Signed-off-by Sasha Levin <[email protected]>
Hi Greg/Sasha,
I ran an AI-assisted backport review, and I have verified the report. It looks valid to me.
The 6.12 adaptation publishes __scm before the new completion array is allocated and initialized, and before the waitqueue IRQ is ready. A consumer can therefore observe SCM availability with no usable completion state. If the allocation fails, probe returns while the published global can refer to released devres storage.
Upstream code after both ordering prerequisites:
ret = devm_request_threaded_irq(scm->dev, irq, NULL,
qcom_scm_irq_handler, IRQF_ONESHOT,
"qcom-scm", scm);
if (ret < 0)
return dev_err_probe(scm->dev, ret,
"Failed to request qcom-scm irq\n");
smp_store_release(&__scm, scm);Downstream 6.12.y code:
smp_store_release(&__scm, scm);
scm->waitq_comps =
devm_kcalloc(&pdev->dev, scm->wq_cnt,
sizeof(*scm->waitq_comps), GFP_KERNEL);
ret = devm_request_threaded_irq(__scm->dev, irq, NULL,
qcom_scm_irq_handler, IRQF_ONESHOT,
"qcom-scm", __scm);Upstream publishes __scm only after both the TZMem allocator and waitqueue IRQ are ready, as established by bcd14791ba62d2 and 4e06c33aaa5ddc
Maybe we should be applying those backports ? Thoughts?
thanks,
Harshit> ---
Quoted 151 lines
drivers/firmware/qcom/qcom_scm.c | 72 ++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 22 deletions(-)drivers/firmware/qcom/qcom_scm.c +50
-22@@ -48,7 +48,7 @@ struct qcom_scm {struct clk *iface_clk;struct clk *bus_clk;struct icc_path *path; -struct completion waitq_comp; +struct completion *waitq_comps;struct reset_controller_dev reset;/* control access to the interconnect path */ @@ -58,6 +58,7 @@ struct qcom_scm {u64 dload_mode_addr;struct qcom_tzmem_pool *mempool; +unsigned int wq_cnt; };struct qcom_scm_current_perm_info {@@ -137,6 +138,8 @@ static const u8 qcom_scm_cpu_warm_bits[QCOM_SCM_BOOT_MAX_CPUS] = {#define QCOM_DLOAD_MINIDUMP 2#define QCOM_DLOAD_BOTHDUMP 3 +#define QCOM_SCM_DEFAULT_WAITQ_COUNT 1 +static const char *const qcom_scm_convention_names[] = { [SMC_CONVENTION_UNKNOWN ] ="unknown" , [SMC_CONVENTION_ARM_32 ] ="smc arm 32" ,@@ -1873,6 +1876,23 @@ static int qcom_scm_fill_irq_fwspec_params(struct irq_fwspec *fwspec, u32 hwirq)return 0 ; } +static int qcom_scm_query_waitq_count (struct qcom_scm *scm) +{ +struct qcom_scm_desc desc = { + .svc =QCOM_SCM_SVC_WAITQ , + .cmd =QCOM_SCM_WAITQ_GET_INFO , + .owner =ARM_SMCCC_OWNER_SIP + }; +struct qcom_scm_res res; +int ret; + + ret =qcom_scm_call_atomic (scm->dev, &desc, &res); +if (ret) +return ret; + +return res.result[0 ] &GENMASK (7 ,0 ); +} +static int qcom_scm_get_waitq_irq (struct qcom_scm *scm) {struct qcom_scm_desc desc = {@@ -1904,42 +1924,40 @@ static int qcom_scm_get_waitq_irq(struct qcom_scm *scm)return irq_create_fwspec_mapping (&fwspec); } -static int qcom_scm_assert_valid_wq_ctx (u32 wq_ctx) +static struct completion *qcom_scm_get_completion (u32 wq_ctx) { -/* FW currently only supports a single wq_ctx (zero). -* TODO: Update this logic to include dynamic allocation and lookup of -* completion structs when FW supports more wq_ctx values. -*/ -if (wq_ctx !=0 ) { -dev_err (__scm->dev,"Firmware unexpectedly passed non-zero wq_ctx\n" ); -return -EINVAL ; - } +struct completion *wq; -return 0 ; +if (WARN_ON_ONCE (wq_ctx >= __scm->wq_cnt)) +return ERR_PTR (-EINVAL ); + + wq = &__scm->waitq_comps[wq_ctx]; + +return wq; }int qcom_scm_wait_for_wq_completion (u32 wq_ctx) { -int ret; +struct completion *wq; - ret =qcom_scm_assert_valid_wq_ctx (wq_ctx); -if (ret) -return ret; + wq =qcom_scm_get_completion (wq_ctx); +if (IS_ERR (wq)) +return PTR_ERR (wq); -wait_for_completion (&__scm->waitq_comp); +wait_for_completion (wq);return 0 ; }static int qcom_scm_waitq_wakeup (unsigned int wq_ctx) { -int ret; +struct completion *wq; - ret =qcom_scm_assert_valid_wq_ctx (wq_ctx); -if (ret) -return ret; + wq =qcom_scm_get_completion (wq_ctx); +if (IS_ERR (wq)) +return PTR_ERR (wq); -complete (&__scm->waitq_comp); +complete (wq);return 0 ; }@@ -2015,6 +2033,7 @@ static int qcom_scm_probe(struct platform_device *pdev)struct qcom_tzmem_pool_config pool_config;struct qcom_scm *scm;int irq, ret; +int i; scm =devm_kzalloc (&pdev->dev,sizeof (*scm),GFP_KERNEL );if (!scm)@@ -2025,7 +2044,6 @@ static int qcom_scm_probe(struct platform_device *pdev)if (ret <0 )return ret; -init_completion (&scm->waitq_comp);mutex_init (&scm->scm_bw_lock); scm->path =devm_of_icc_get (&pdev->dev,NULL );@@ -2060,6 +2078,16 @@ static int qcom_scm_probe(struct platform_device *pdev)/* Paired with smp_load_acquire() in qcom_scm_is_available(). */ smp_store_release (&__scm, scm); + ret =qcom_scm_query_waitq_count (scm); + scm->wq_cnt = ret <0 ?QCOM_SCM_DEFAULT_WAITQ_COUNT : ret; + scm->waitq_comps =devm_kcalloc (&pdev->dev, scm->wq_cnt,sizeof (*scm->waitq_comps), +GFP_KERNEL ); +if (!scm->waitq_comps) +return -ENOMEM ; + +for (i =0 ; i < scm->wq_cnt; i++) +init_completion (&scm->waitq_comps[i]); + irq =qcom_scm_get_waitq_irq (scm);if (irq <0 ) irq =platform_get_irq_optional (pdev,0 );
Sasha Levin
maintainerRe: [PATCH 6.12 0760/1376] firmware: qcom_scm: Support multiple waitq contexts
Quoted 4 lines
Upstream publishes
__scmonly after both the TZMem allocator and waitqueue IRQ are ready, as established bybcd14791ba62d2and4e06c33aaa5ddcMaybe we should be applying those backports ? Thoughts?
That chain cannot land on 6.12 any more. The tree already released da9e6b1a96b1 ("firmware: qcom_scm: Add API to get waitqueue IRQ info") and ccd207ec848e ("firmware: qcom_scm: Support multiple waitq contexts"), both mainline descendants of 7ab36b51c6be ("firmware: qcom: scm: request the waitqueue irq *after* initializing SCM"), backported ahead of it. Their waitq code now sits inside the very window 7ab36b51c6be has to hoist, and no extra dependency repairs that.
Tested backports would be more than welcome here.
Signature · 2 lines
Thanks, Sasha
Greg Kroah-Hartman
maintainerPATCH 761/1376 firmware: qcom: scm: add trace events for the SMC call interface
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuvaraj Ranganathan <[email protected]>
[ Upstream commit f6bb2daa4584229af155c2488b83151999315293 ]
The SCM SMC call path is opaque at runtime. Stalls caused by firmware congestion, QCOM_SCM_WAITQ_SLEEP/RESUME cycles, and EBUSY retry loops are invisible without recompiling the kernel with temporary printk statements or attaching a hardware debugger.
Add five TRACE_EVENTs covering the complete lifecycle of an SCM call:
scm_smc_request
Emit before each arm_smccc_smc_quirk() invocation. Records the SMC function ID, decoded service and command identifiers, argument count, and up to six register arguments in hex and decimal. Because the caller loops on QCOM_SCM_INTERRUPTED, this event fires once per physical SMC instruction including inte
scm_smc_done
Emit after the outer __scm_smc_do() returns, pairing each request with its final outcome. Records the SMC function ID, the kernel error code returned to the caller, and the four firmware result registers a0-a3.
scm_waitq_sleep
Emit when the firmware returns QCOM_SCM_WAITQ_SLEEP. Records the wait-queue context and the SMC call context handles required to issue the matching WAITQ_RESUME.
scm_waitq_resume
Emit just before constructing and sending the WAITQ_RESUME follow-up call. Records the SMC call context handle being resumed.
scm_waitq_get_wq_ctx
Emit after a successful WAITQ_GET_WQ_CTX fast-call. Records the returned wait-queue context, flags, and more_pending indicator.
These events let ftrace and perf reconstruct the full sequence of firmware interactions, measure per-call and end-to-end latency, and attribute waitqueue stalls to specific service/command pairs without modifying driver source.
Stable-dep-of: 966d23c7e68e ("firmware: qcom: scm: Fix NULL dereference in IRQ handler before __scm is published")
--- drivers/firmware/qcom/qcom_scm_trace.h | 143 +++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 drivers/firmware/qcom/qcom_scm_trace.h
drivers/firmware/qcom/qcom_scm_trace.h new file +143 -0
@@ -0,0 +1,143 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* +* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +*/ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM qcom_scm + +#if !defined(_TRACE_SCM_SMC_INTERFACE_H) || defined(TRACE_HEADER_MULTI_READ ) + +#define _TRACE_SCM_SMC_INTERFACE_H + +#include <linux/tracepoint.h> + +TRACE_EVENT (scm_smc_request, + + TP_PROTO(unsigned long a0, const struct arm_smccc_args *smc), + +TP_ARGS (a0, smc), + +TP_STRUCT__entry ( + __field(u64, smc_id) + __field(u8, svc_id) + __field(u8, cmd_id) + __field(u8, args_cnt) + __dynamic_array(unsigned long, args, +min_t (u8, (smc->args[1 ] &0xF ), (u8 )6 )) + ), + +TP_fast_assign ( + __entry->smc_id = a0; + __entry->svc_id = (smc->args[0] >> 8) & 0xFF; + __entry->cmd_id = smc->args[0] & 0xFF; + u8 n = min_t(u8, (smc->args[1] & 0xF), (u8)6); + + __entry->args_cnt = n; + + unsigned long *dst = __get_dynamic_array(args); + + for (int i = 0; i < n; i++) + dst[i] = smc->args[2 + i]; + ), + +TP_printk ("smc_id:0x%08llx svc_id:0x%02x cmd_id:0x%02x args_cnt:%u args:%s" , + __entry->smc_id, __entry->svc_id, __entry->cmd_id, __entry->args_cnt, +__print_dynamic_array (args,sizeof (unsigned long ))) +); + +TRACE_EVENT (scm_waitq_sleep, + + TP_PROTO(u32 wq_ctx, u32 smc_ctx), + +TP_ARGS (wq_ctx, smc_ctx), + +TP_STRUCT__entry ( + __field(u32, wq_ctx) +__field (u32, smc_call_ctx) + ), + +TP_fast_assign ( + __entry->wq_ctx = wq_ctx; + __entry->smc_call_ctx = smc_ctx; + ), + +TP_printk ("wq_ctx:%u, smc_call_ctx:%u" , __entry->wq_ctx, __entry->smc_call_ctx) +); + +TRACE_EVENT (scm_waitq_resume, + + TP_PROTO(u32 smc_ctx), + +TP_ARGS (smc_ctx), + +TP_STRUCT__entry ( +__field (u32, smc_call_ctx) + ), + +TP_fast_assign ( + __entry->smc_call_ctx = smc_ctx; + ), + +TP_printk ("smc_call_ctx:%u" , __entry->smc_call_ctx) +); + +TRACE_EVENT (scm_waitq_get_wq_ctx, + + TP_PROTO(u32 wq_ctx, u32 flags, u32 pending), + +TP_ARGS (wq_ctx, flags, pending), + +TP_STRUCT__entry ( + __field(u32, wq_ctx) + __field(u32, flags) +__field (u32, more_pending) + ), + +TP_fast_assign ( + __entry->wq_ctx = wq_ctx; + __entry->flags = flags; + __entry->more_pending = pending; + ), + +TP_printk ("wq_ctx:%u, flags:%u, more_pending:%u" , + __entry->wq_ctx, __entry->flags, __entry->more_pending) +); + +TRACE_EVENT (scm_smc_done, + + TP_PROTO(int ret, u64 smc_id, struct arm_smccc_res *smc_res), + +TP_ARGS (ret, smc_id, smc_res), + +TP_STRUCT__entry ( + __field(int, ret) + __field(u64, smc_id) + __field(unsigned long, res) + __field(unsigned long, res0) + __field(unsigned long, res1) + __field(unsigned long, res2) + ), + +TP_fast_assign ( + __entry->ret = ret; + __entry->smc_id = smc_id; + __entry->res = smc_res->a0; + __entry->res0 = smc_res->a1; + __entry->res1 = smc_res->a2; + __entry->res2 = smc_res->a3; + ), + +TP_printk ("smc_id:0x%08llx, ret:%d res_to_callee:0x%lx res0:0x%lx res1:0x%lx res2:0x%lx" , + __entry->smc_id, __entry->ret, __entry->res, + __entry->res0, __entry->res1, __entry->res2) +); + +#endif /* _TRACE_SCM_SMC_INTERFACE_H */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE qcom_scm_trace + +#include <trace/define_trace.h> +
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 762/1376 firmware: qcom: scm: instrument SMC call path with tracepoints
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuvaraj Ranganathan <[email protected]>
[ Upstream commit 41329e72363c02facfeae063ef304aa7ced68c3b ]
Wire the five tracepoints defined in qcom_scm_trace.h into the SMC execution path by including the header with CREATE_TRACE_POINTS.
Stable-dep-of: 966d23c7e68e ("firmware: qcom: scm: Fix NULL dereference in IRQ handler before __scm is published")
--- drivers/firmware/qcom/Makefile | 1 + drivers/firmware/qcom/qcom_scm-smc.c | 10 ++++++++++ 2 files changed, 11 insertions(+)
drivers/firmware/qcom/Makefile +1 -0
@@ -5,6 +5,7 @@ obj-$(CONFIG_QCOM_SCM) += qcom-scm.o qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o +CFLAGS_qcom_scm-smc.o := -I$(src) obj-$(CONFIG_QCOM_TZMEM) += qcom_tzmem.o obj-$(CONFIG_QCOM_QSEECOM) += qcom_qseecom.o obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o
drivers/firmware/qcom/qcom_scm-smc.c +10 -0
@@ -24,6 +24,9 @@ struct arm_smccc_args {unsigned long args[8 ]; }; +#define CREATE_TRACE_POINTS +#include "qcom_scm_trace.h" +static DEFINE_MUTEX (qcom_scm_lock);#define QCOM_SCM_EBUSY_WAIT_MS 30
@@ -44,6 +47,7 @@ static void __scm_smc_do_quirk(const struct arm_smccc_args *smc, quirk.state.a6 =0 ; do { + trace_scm_smc_request(a0, smc); arm_smccc_smc_quirk(a0, smc->args[1], smc->args[2], smc->args[3], smc->args[4], smc->args[5], quirk.state.a6, smc->args[7], res, &quirk);
@@ -83,6 +87,7 @@ int scm_get_wq_ctx(u32 *wq_ctx, u32 *flags, u32 *more_pending)if (ret)return ret; +trace_scm_waitq_get_wq_ctx (get_wq_res.a1, get_wq_res.a2, get_wq_res.a3); *wq_ctx = get_wq_res.a1; *flags = get_wq_res.a2; *more_pending = get_wq_res.a3;
@@ -105,10 +110,12 @@ static int __scm_smc_do_quirk_handle_waitq(struct device *dev, struct arm_smccc_ wq_ctx = res->a1; smc_call_ctx = res->a2; +trace_scm_waitq_sleep (wq_ctx, smc_call_ctx); ret =qcom_scm_wait_for_wq_completion (wq_ctx);if (ret)return ret; +trace_scm_waitq_resume (smc_call_ctx);fill_wq_resume_args (&resume, smc_call_ctx); smc = &resume; }
@@ -200,6 +207,9 @@ int __scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc, } ret =__scm_smc_do (dev, &smc, &smc_res, atomic); + +trace_scm_smc_done (ret, smc.args[0 ], &smc_res); +if (ret)return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 763/1376 firmware: qcom: scm: Fix NULL dereference in IRQ handler before __scm is published
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mukesh Ojha <[email protected]>
[ Upstream commit 966d23c7e68ea32679275a7e3d2383181002c868 ]
In qcom_scm_probe(), devm_request_threaded_irq() is called before smp_store_release(&__scm, scm). Two paths can dereference __scm before it is published, both causing a NULL pointer dereference.
The IRQ handler receives scm via its data argument but passes only wq_ctx to qcom_scm_waitq_wakeup() and qcom_scm_get_completion(), which then dereference __scm directly. Thread scm through both functions so the IRQ handler path never touches __scm.
Non-atomic SMC calls made during probe (e.g. from qcom_tzmem_init via qcom_scm_shm_bridge_enable) can return WAITQ_SLEEP, causing qcom_scm_wait_for_wq_completion() to run before __scm is published and dereference it. Add platform_set_drvdata(pdev, scm) early in probe and change qcom_scm_wait_for_wq_completion() to take the device pointer and use dev_get_drvdata() to reach scm, removing any dependency on __scm.
--- drivers/firmware/qcom/qcom_scm-smc.c | 2 +- drivers/firmware/qcom/qcom_scm.c | 22 ++++++++++------------ drivers/firmware/qcom/qcom_scm.h | 2 +- 3 files changed, 12 insertions(+), 14 deletions(-)
drivers/firmware/qcom/qcom_scm-smc.c +1 -1
@@ -111,7 +111,7 @@ static int __scm_smc_do_quirk_handle_waitq(struct device *dev, struct arm_smccc_ smc_call_ctx = res->a2;trace_scm_waitq_sleep (wq_ctx, smc_call_ctx); - ret =qcom_scm_wait_for_wq_completion (wq_ctx); + ret =qcom_scm_wait_for_wq_completion (dev, wq_ctx);if (ret)return ret;
drivers/firmware/qcom/qcom_scm.c +10 -12
@@ -1924,23 +1924,20 @@ static int qcom_scm_get_waitq_irq(struct qcom_scm *scm)return irq_create_fwspec_mapping (&fwspec); } -static struct completion *qcom_scm_get_completion (u32 wq_ctx) +static struct completion *qcom_scm_get_completion (struct qcom_scm *scm,u32 wq_ctx) { -struct completion *wq; - -if (WARN_ON_ONCE (wq_ctx >= __scm->wq_cnt)) +if (WARN_ON_ONCE (wq_ctx >= scm->wq_cnt))return ERR_PTR (-EINVAL ); - wq = &__scm->waitq_comps[wq_ctx]; - -return wq; +return &scm->waitq_comps[wq_ctx]; } -int qcom_scm_wait_for_wq_completion (u32 wq_ctx) +int qcom_scm_wait_for_wq_completion (struct device *dev,u32 wq_ctx) { +struct qcom_scm *scm =dev_get_drvdata (dev);struct completion *wq; - wq =qcom_scm_get_completion (wq_ctx); + wq =qcom_scm_get_completion (scm, wq_ctx);if (IS_ERR (wq))return PTR_ERR (wq);
@@ -1949,11 +1946,11 @@ int qcom_scm_wait_for_wq_completion(u32 wq_ctx)return 0 ; } -static int qcom_scm_waitq_wakeup (unsigned int wq_ctx) +static int qcom_scm_waitq_wakeup (struct qcom_scm *scm,unsigned int wq_ctx) {struct completion *wq; - wq =qcom_scm_get_completion (wq_ctx); + wq =qcom_scm_get_completion (scm, wq_ctx);if (IS_ERR (wq))return PTR_ERR (wq);
@@ -1980,7 +1977,7 @@ static irqreturn_t qcom_scm_irq_handler(int irq, void *data) goto out; } - ret =qcom_scm_waitq_wakeup (wq_ctx); + ret =qcom_scm_waitq_wakeup (scm, wq_ctx);if (ret) goto out; }while (more_pending);
@@ -2040,6 +2037,7 @@ static int qcom_scm_probe(struct platform_device *pdev)return -ENOMEM ; scm->dev = &pdev->dev; +platform_set_drvdata (pdev, scm); ret =qcom_scm_find_dload_address (&pdev->dev, &scm->dload_mode_addr);if (ret <0 )return ret;
drivers/firmware/qcom/qcom_scm.h +1 -1
@@ -63,7 +63,7 @@ struct qcom_scm_res {u64 result[MAX_QCOM_SCM_RETS ]; }; -int qcom_scm_wait_for_wq_completion (u32 wq_ctx); +int qcom_scm_wait_for_wq_completion (struct device *dev,u32 wq_ctx);int scm_get_wq_ctx (u32 *wq_ctx,u32 *flags,u32 *more_pending);#define SCM_SMC_FNID (s, c) ((((s) & 0xFF) << 8) | ((c) & 0xFF))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 764/1376 firmware: qcom: scm: Fix tzmem state on probe retry
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mukesh Ojha <[email protected]>
[ Upstream commit 9941fe8a04f3d258e07eb5899db3027252a4190f ]
qcom_tzmem_enable() returns -EBUSY if called a second time, but this causes probe retries to fail permanently if a later step in qcom_scm_probe() defers after qcom_tzmem_enable() has already succeeded.
Use DO_ONCE() to ensure qcom_tzmem_init() runs exactly once across all calls in a thread-safe manner. qcom_tzmem_dev is set on every call since probe retries use the same device pointer. The result of the first initialisation is cached and returned to every subsequent caller.
--- drivers/firmware/qcom/qcom_tzmem.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
drivers/firmware/qcom/qcom_tzmem.c +9 -4
@@ -15,6 +15,7 @@#include <linux/kernel.h> #include <linux/list.h> #include <linux/mm.h> +#include <linux/once.h> #include <linux/radix-tree.h> #include <linux/slab.h> #include <linux/spinlock.h>
@@ -465,14 +466,18 @@ phys_addr_t qcom_tzmem_to_phys(void *vaddr) }EXPORT_SYMBOL_GPL (qcom_tzmem_to_phys); +static void qcom_tzmem_do_init (int *result) +{ + *result =qcom_tzmem_init (); +} +int qcom_tzmem_enable (struct device *dev) { -if (qcom_tzmem_dev) -return -EBUSY ; +static int result; qcom_tzmem_dev = dev; - -return qcom_tzmem_init (); +DO_ONCE (qcom_tzmem_do_init, &result); +return result; }EXPORT_SYMBOL_GPL (qcom_tzmem_enable);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 765/1376 arm64: dts: qcom: sm8250-xiaomi-elish: correct the board ID
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dawid Wróbel <[email protected]>
[ Upstream commit 299731d4fbeaaa141ce2e8226ca00cb30d6ab647 ]
elish declares the same qcom,msm-id and qcom,board-id pair as sm8250-sony-xperia-edo.dtsi, so a bootloader choosing between appended device trees cannot tell the two boards apart.
0x10008 is Sony's value. The downstream device tree for this board, elish-sm8250-overlay.dts, uses qcom,board-id = <47 0>, i.e. platform type 0x2f.
--- arch/arm64/boot/dts/qcom/sm8250-xiaomi-elish-common.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm64/boot/dts/qcom/sm8250-xiaomi-elish-common.dtsi +1 -1
@@ -28,7 +28,7 @@ / { /* required for bootloader to select correct board */ qcom,msm-id = <QCOM_ID_SM8250 0x20001>; /* SM8250 v2.1 */ - qcom,board-id = <0x10008 0>; + qcom,board-id = <0x2f 0>; chosen { #address-cells = <2>;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 766/1376 arm64: dts: qcom: sc8180x: Fix the PCIe iommu-map entries
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <[email protected]>
[ Upstream commit a4548204821a56c23cd711cfad2a637ca055ff47 ]
The IOMMU provider apps_smmu uses '#iommu-cells = <2>', but the PCIe iommu-map entries specify only one cell for the SID, omitting the SID mask. This went unnoticed until the OF core started warning with commit ccb2fd725d41 ("of: Respect #{iommu,msi}-cells in maps"):
iommu-map has 1-cell entries targeting 2-cell #iommu-cells, treating as 1-cell output
So fix the entries to match the provider's '#iommu-cells' property.
--- arch/arm64/boot/dts/qcom/sc8180x.dtsi | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
arch/arm64/boot/dts/qcom/sc8180x.dtsi +8 -8
@@ -1761,8 +1761,8 @@ pcie0: pcie@1c00000 { assigned-clocks = <&gcc GCC_PCIE_0_AUX_CLK>; assigned-clock-rates = <19200000>; - iommu-map = <0x0 &apps_smmu 0x1d80 0x1>, - <0x100 &apps_smmu 0x1d81 0x1>; + iommu-map = <0x0 &apps_smmu 0x1d80 0x0 0x1>, + <0x100 &apps_smmu 0x1d81 0x0 0x1>; resets = <&gcc GCC_PCIE_0_BCR>; reset-names = "pci";
@@ -1882,8 +1882,8 @@ pcie3: pcie@1c08000 { assigned-clocks = <&gcc GCC_PCIE_3_AUX_CLK>; assigned-clock-rates = <19200000>; - iommu-map = <0x0 &apps_smmu 0x1e00 0x1>, - <0x100 &apps_smmu 0x1e01 0x1>; + iommu-map = <0x0 &apps_smmu 0x1e00 0x0 0x1>, + <0x100 &apps_smmu 0x1e01 0x0 0x1>; resets = <&gcc GCC_PCIE_3_BCR>; reset-names = "pci";
@@ -2004,8 +2004,8 @@ pcie1: pcie@1c10000 { assigned-clocks = <&gcc GCC_PCIE_1_AUX_CLK>; assigned-clock-rates = <19200000>; - iommu-map = <0x0 &apps_smmu 0x1c80 0x1>, - <0x100 &apps_smmu 0x1c81 0x1>; + iommu-map = <0x0 &apps_smmu 0x1c80 0x0 0x1>, + <0x100 &apps_smmu 0x1c81 0x0 0x1>; resets = <&gcc GCC_PCIE_1_BCR>; reset-names = "pci";
@@ -2126,8 +2126,8 @@ pcie2: pcie@1c18000 { assigned-clocks = <&gcc GCC_PCIE_2_AUX_CLK>; assigned-clock-rates = <19200000>; - iommu-map = <0x0 &apps_smmu 0x1d00 0x1>, - <0x100 &apps_smmu 0x1d01 0x1>; + iommu-map = <0x0 &apps_smmu 0x1d00 0x0 0x1>, + <0x100 &apps_smmu 0x1d01 0x0 0x1>; resets = <&gcc GCC_PCIE_2_BCR>; reset-names = "pci";
Signature · 1 line
2.53.0
Re: [PATCH 6.12 0766/1376] arm64: dts: qcom: sc8180x: Fix the PCIe iommu-map entries
Quoted 17 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <[email protected]>
[ Upstream commit
a4548204821a56c23cd711cfad2a637ca055ff47]The IOMMU provider
apps_smmuuses '#iommu-cells = <2>', but the PCIe iommu-map entries specify only one cell for the SID, omitting the SID mask. This went unnoticed until the OF core started warning with commitccb2fd725d41("of: Respect #{iommu,msi}-cells in maps"):iommu-map has 1-cell entries targeting 2-cell #iommu-cells, treating as 1-cell output
So fix the entries to match the provider's '#iommu-cells' property.
Quoted 7 lines
Fixes d20b6c84f56a ("arm64: dts: qcom: sc8180x: Add PCIe instances")Signed-off-by Manivannan Sadhasivam <[email protected]>Reviewed-by Konrad Dybcio <[email protected]>Reviewed-by Dmitry Baryshkov <[email protected]>Signed-off-by Bjorn Andersson <[email protected]>Signed-off-by Sasha Levin <[email protected]>
Hi Greg/Sasha,
I ran an AI-assisted backport review, and I have verified the report. It looks valid to me.
The corrected SC8180x properties contain two five-cell iommu-map entries, but 6.12's of_map_id() accepts only fixed four-cell entries. Each 40-byte property fails the 16-byte divisibility check and returns EINVAL before any requester-ID mapping. The PCI setup path can continue without the intended IOMMU configuration.
Upstream has the variable-cell parser and its API preparation series, including ccb2fd725d411265df8f7ce12a66c226b16014e6. That broad series is absent here.
Maybe we should this isolated DTS patch. Thoughts?
thanks,
Harshit> ---
Quoted 51 lines
arch/arm64/boot/dts/qcom/sc8180x.dtsi | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)arch/arm64/boot/dts/qcom/sc8180x.dtsi +8
-8@@ -1761,8 +1761,8 @@ pcie0: pcie@1c00000 { assigned-clocks = <&gcc GCC_PCIE_0_AUX_CLK>; assigned-clock-rates = <19200000>; - iommu-map = <0x0 &apps_smmu 0x1d80 0x1>, - <0x100 &apps_smmu 0x1d81 0x1>; + iommu-map = <0x0 &apps_smmu 0x1d80 0x0 0x1>, + <0x100 &apps_smmu 0x1d81 0x0 0x1>; resets = <&gcc GCC_PCIE_0_BCR>; reset-names = "pci";@@ -1882,8 +1882,8 @@ pcie3: pcie@1c08000 { assigned-clocks = <&gcc GCC_PCIE_3_AUX_CLK>; assigned-clock-rates = <19200000>; - iommu-map = <0x0 &apps_smmu 0x1e00 0x1>, - <0x100 &apps_smmu 0x1e01 0x1>; + iommu-map = <0x0 &apps_smmu 0x1e00 0x0 0x1>, + <0x100 &apps_smmu 0x1e01 0x0 0x1>; resets = <&gcc GCC_PCIE_3_BCR>; reset-names = "pci";@@ -2004,8 +2004,8 @@ pcie1: pcie@1c10000 { assigned-clocks = <&gcc GCC_PCIE_1_AUX_CLK>; assigned-clock-rates = <19200000>; - iommu-map = <0x0 &apps_smmu 0x1c80 0x1>, - <0x100 &apps_smmu 0x1c81 0x1>; + iommu-map = <0x0 &apps_smmu 0x1c80 0x0 0x1>, + <0x100 &apps_smmu 0x1c81 0x0 0x1>; resets = <&gcc GCC_PCIE_1_BCR>; reset-names = "pci";@@ -2126,8 +2126,8 @@ pcie2: pcie@1c18000 { assigned-clocks = <&gcc GCC_PCIE_2_AUX_CLK>; assigned-clock-rates = <19200000>; - iommu-map = <0x0 &apps_smmu 0x1d00 0x1>, - <0x100 &apps_smmu 0x1d01 0x1>; + iommu-map = <0x0 &apps_smmu 0x1d00 0x0 0x1>, + <0x100 &apps_smmu 0x1d01 0x0 0x1>; resets = <&gcc GCC_PCIE_2_BCR>; reset-names = "pci";
Re: [PATCH 6.12 0766/1376] arm64: dts: qcom: sc8180x: Fix the PCIe iommu-map entries
Quoted 40 lines · Harshit Mogalapalli
Quoted 17 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <[email protected]>
[ Upstream commit
a4548204821a56c23cd711cfad2a637ca055ff47]The IOMMU provider
apps_smmuuses '#iommu-cells = <2>', but the PCIe iommu-map entries specify only one cell for the SID, omitting the SID mask. This went unnoticed until the OF core started warning with commitccb2fd725d41("of: Respect #{iommu,msi}-cells in maps"):iommu-map has 1-cell entries targeting 2-cell #iommu-cells, treating as 1-cell output
So fix the entries to match the provider's '#iommu-cells' property.
Quoted 7 lines
Fixes d20b6c84f56a ("arm64: dts: qcom: sc8180x: Add PCIe instances")Signed-off-by Manivannan Sadhasivam <[email protected]>Reviewed-by Konrad Dybcio <[email protected]>Reviewed-by Dmitry Baryshkov <[email protected]>Signed-off-by Bjorn Andersson <[email protected]>Signed-off-by Sasha Levin <[email protected]>Hi Greg/Sasha,
I ran an AI-assisted backport review, and I have verified the report. It looks valid to me.
The corrected SC8180x properties contain two five-cell iommu-map entries, but 6.12's
of_map_id()accepts only fixed four-cell entries. Each 40-byte property fails the 16-byte divisibility check and returns EINVAL before any requester-ID mapping. The PCI setup path can continue without the intended IOMMU configuration.
Quoted 5 lines
Upstream has the variable-cell parser and its API preparation series, including
ccb2fd725d411265df8f7ce12a66c226b16014e6. That broad series is absent here.Maybe we should this isolated DTS patch. Thoughts?
Yes, all changes of this kind (conveniently similarly named and IIRC they all got merged in one go) should be dropped from the trees that don't have the parser change
Konrad
Sasha Levin
maintainerRe: [PATCH 6.12 0766/1376] arm64: dts: qcom: sc8180x: Fix the PCIe iommu-map entries
In reply to Harshit MogalapalliQuoted 3 lines
Upstream has the variable-cell parser and its API preparation series, including
ccb2fd725d411265df8f7ce12a66c226b16014e6. That broad series is absent here.
Agreed, and Konrad asked for the whole family to come out of every tree that lacks ccb2fd725d41 ("of: Respect #{iommu,msi}-cells in maps").
Reverted across 6.18, 6.12, 6.6 and 6.1, 35 commits in total. 7.2 has the parser, so it keeps them. The msi-map siblings stay as they are.
Signature · 2 lines
Thanks, Sasha
Re: [PATCH 6.12 0766/1376] arm64: dts: qcom: sc8180x: Fix the PCIe iommu-map entries
Quoted 9 lines · Sasha Levin
Quoted 3 lines
Upstream has the variable-cell parser and its API preparation series, including
ccb2fd725d411265df8f7ce12a66c226b16014e6. That broad series is absent here.Agreed, and Konrad asked for the whole family to come out of every tree that lacks
ccb2fd725d41("of: Respect #{iommu,msi}-cells in maps").Reverted across 6.18, 6.12, 6.6 and 6.1, 35 commits in total. 7.2 has the parser, so it keeps them. The msi-map siblings stay as they are.
I think the updated msi-maps parsing would be broken without that commit too, no?
Konrad
Re: [PATCH 6.12 0766/1376] arm64: dts: qcom: sc8180x: Fix the PCIe iommu-map entries
Quoted 5 lines · Konrad Dybcio
Quoted 4 lines · Sasha Levin
Quoted 3 lines
Upstream has the variable-cell parser and its API preparation series, including
ccb2fd725d411265df8f7ce12a66c226b16014e6. That broad series is absent here.
Quoted 8 lines
Quoted 5 lines
Agreed, and Konrad asked for the whole family to come out of every tree that lacks
ccb2fd725d41("of: Respect #{iommu,msi}-cells in maps").Reverted across 6.18, 6.12, 6.6 and 6.1, 35 commits in total. 7.2 has the parser, so it keeps them. The msi-map siblings stay as they are.
I think the updated msi-maps parsing would be broken without that commit too, no?
For clarity "the updated msi-maps parsing" - "the parsing of the updated msi-map which contains the amount of cells that the iommu node provides, rather than an always-assumed 1"
Konrad
Sasha Levin
maintainerRe: [PATCH 6.12 0766/1376] arm64: dts: qcom: sc8180x: Fix the PCIe iommu-map entries
Quoted 3 lines
For clarity "the updated msi-maps parsing" - "the parsing of the updated msi-map which contains the amount of cells that the iommu node provides, rather than an always-assumed 1"
Which commits do you have in mind? Going through the trees I could not find an msi-map record that was widened the way the iommu-map ones were, either upstream or in stable, and gic_its is #msi-cells = <1> everywhere I looked, so the fixed four cell parse in of_map_id() still reads them correctly without ccb2fd725d41 ("of: Respect #{iommu,msi}-cells in maps").
If you have specific SHAs in mind, name them and I will take them out of the same trees the iommu-map family came out of.
Signature · 2 lines
Thanks, Sasha
Greg Kroah-Hartman
maintainerPATCH 767/1376 arm64: dts: qcom: sdm845: Fix the PCIe iommu-map entries
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <[email protected]>
[ Upstream commit deaea7e982bc353c8d3c406774970f16ed901adb ]
The IOMMU provider apps_smmu uses '#iommu-cells = <2>', but the PCIe iommu-map entries specify only one cell for the SID, omitting the SID mask. This went unnoticed until the OF core started warning with commit ccb2fd725d41 ("of: Respect #{iommu,msi}-cells in maps"):
iommu-map has 1-cell entries targeting 2-cell #iommu-cells, treating as 1-cell output
So fix the entries to match the provider's '#iommu-cells' property.
--- arch/arm64/boot/dts/qcom/sdm845.dtsi | 64 ++++++++++++++-------------- 1 file changed, 32 insertions(+), 32 deletions(-)
arch/arm64/boot/dts/qcom/sdm845.dtsi +32 -32
@@ -2350,22 +2350,22 @@ pcie0: pcie@1c00000 { "slave_q2a", "tbu"; - iommu-map = <0x0 &apps_smmu 0x1c10 0x1>, - <0x100 &apps_smmu 0x1c11 0x1>, - <0x200 &apps_smmu 0x1c12 0x1>, - <0x300 &apps_smmu 0x1c13 0x1>, - <0x400 &apps_smmu 0x1c14 0x1>, - <0x500 &apps_smmu 0x1c15 0x1>, - <0x600 &apps_smmu 0x1c16 0x1>, - <0x700 &apps_smmu 0x1c17 0x1>, - <0x800 &apps_smmu 0x1c18 0x1>, - <0x900 &apps_smmu 0x1c19 0x1>, - <0xa00 &apps_smmu 0x1c1a 0x1>, - <0xb00 &apps_smmu 0x1c1b 0x1>, - <0xc00 &apps_smmu 0x1c1c 0x1>, - <0xd00 &apps_smmu 0x1c1d 0x1>, - <0xe00 &apps_smmu 0x1c1e 0x1>, - <0xf00 &apps_smmu 0x1c1f 0x1>; + iommu-map = <0x0 &apps_smmu 0x1c10 0x0 0x1>, + <0x100 &apps_smmu 0x1c11 0x0 0x1>, + <0x200 &apps_smmu 0x1c12 0x0 0x1>, + <0x300 &apps_smmu 0x1c13 0x0 0x1>, + <0x400 &apps_smmu 0x1c14 0x0 0x1>, + <0x500 &apps_smmu 0x1c15 0x0 0x1>, + <0x600 &apps_smmu 0x1c16 0x0 0x1>, + <0x700 &apps_smmu 0x1c17 0x0 0x1>, + <0x800 &apps_smmu 0x1c18 0x0 0x1>, + <0x900 &apps_smmu 0x1c19 0x0 0x1>, + <0xa00 &apps_smmu 0x1c1a 0x0 0x1>, + <0xb00 &apps_smmu 0x1c1b 0x0 0x1>, + <0xc00 &apps_smmu 0x1c1c 0x0 0x1>, + <0xd00 &apps_smmu 0x1c1d 0x0 0x1>, + <0xe00 &apps_smmu 0x1c1e 0x0 0x1>, + <0xf00 &apps_smmu 0x1c1f 0x0 0x1>; resets = <&gcc GCC_PCIE_0_BCR>; reset-names = "pci";
@@ -2464,22 +2464,22 @@ pcie1: pcie@1c08000 { assigned-clocks = <&gcc GCC_PCIE_1_AUX_CLK>; assigned-clock-rates = <19200000>; - iommu-map = <0x0 &apps_smmu 0x1c00 0x1>, - <0x100 &apps_smmu 0x1c01 0x1>, - <0x200 &apps_smmu 0x1c02 0x1>, - <0x300 &apps_smmu 0x1c03 0x1>, - <0x400 &apps_smmu 0x1c04 0x1>, - <0x500 &apps_smmu 0x1c05 0x1>, - <0x600 &apps_smmu 0x1c06 0x1>, - <0x700 &apps_smmu 0x1c07 0x1>, - <0x800 &apps_smmu 0x1c08 0x1>, - <0x900 &apps_smmu 0x1c09 0x1>, - <0xa00 &apps_smmu 0x1c0a 0x1>, - <0xb00 &apps_smmu 0x1c0b 0x1>, - <0xc00 &apps_smmu 0x1c0c 0x1>, - <0xd00 &apps_smmu 0x1c0d 0x1>, - <0xe00 &apps_smmu 0x1c0e 0x1>, - <0xf00 &apps_smmu 0x1c0f 0x1>; + iommu-map = <0x0 &apps_smmu 0x1c00 0x0 0x1>, + <0x100 &apps_smmu 0x1c01 0x0 0x1>, + <0x200 &apps_smmu 0x1c02 0x0 0x1>, + <0x300 &apps_smmu 0x1c03 0x0 0x1>, + <0x400 &apps_smmu 0x1c04 0x0 0x1>, + <0x500 &apps_smmu 0x1c05 0x0 0x1>, + <0x600 &apps_smmu 0x1c06 0x0 0x1>, + <0x700 &apps_smmu 0x1c07 0x0 0x1>, + <0x800 &apps_smmu 0x1c08 0x0 0x1>, + <0x900 &apps_smmu 0x1c09 0x0 0x1>, + <0xa00 &apps_smmu 0x1c0a 0x0 0x1>, + <0xb00 &apps_smmu 0x1c0b 0x0 0x1>, + <0xc00 &apps_smmu 0x1c0c 0x0 0x1>, + <0xd00 &apps_smmu 0x1c0d 0x0 0x1>, + <0xe00 &apps_smmu 0x1c0e 0x0 0x1>, + <0xf00 &apps_smmu 0x1c0f 0x0 0x1>; resets = <&gcc GCC_PCIE_1_BCR>; reset-names = "pci";
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 768/1376 arm64: dts: qcom: sm8150: Fix the PCIe iommu-map entries
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <[email protected]>
[ Upstream commit d2e56fb42e3d10d7e711063cdc00523ddb31d544 ]
The IOMMU provider apps_smmu uses '#iommu-cells = <2>', but the PCIe iommu-map entries specify only one cell for the SID, omitting the SID mask. This went unnoticed until the OF core started warning with commit ccb2fd725d41 ("of: Respect #{iommu,msi}-cells in maps"):
iommu-map has 1-cell entries targeting 2-cell #iommu-cells, treating as 1-cell output
So fix the entries to match the provider's '#iommu-cells' property.
--- arch/arm64/boot/dts/qcom/sm8150.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
arch/arm64/boot/dts/qcom/sm8150.dtsi +4 -4
@@ -1885,8 +1885,8 @@ pcie0: pcie@1c00000 { "tbu", "ref"; - iommu-map = <0x0 &apps_smmu 0x1d80 0x1>, - <0x100 &apps_smmu 0x1d81 0x1>; + iommu-map = <0x0 &apps_smmu 0x1d80 0x0 0x1>, + <0x100 &apps_smmu 0x1d81 0x0 0x1>; resets = <&gcc GCC_PCIE_0_BCR>; reset-names = "pci";
@@ -2005,8 +2005,8 @@ pcie1: pcie@1c08000 { assigned-clocks = <&gcc GCC_PCIE_1_AUX_CLK>; assigned-clock-rates = <19200000>; - iommu-map = <0x0 &apps_smmu 0x1e00 0x1>, - <0x100 &apps_smmu 0x1e01 0x1>; + iommu-map = <0x0 &apps_smmu 0x1e00 0x0 0x1>, + <0x100 &apps_smmu 0x1e01 0x0 0x1>; resets = <&gcc GCC_PCIE_1_BCR>; reset-names = "pci";
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 769/1376 arm64: dts: qcom: sm8250: Fix the PCIe iommu-map entries
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <[email protected]>
[ Upstream commit c41749e9554d4e03e7074f5d1e46140bc4ac77bd ]
The IOMMU provider apps_smmu uses '#iommu-cells = <2>', but the PCIe iommu-map entries specify only one cell for the SID, omitting the SID mask. This went unnoticed until the OF core started warning with commit ccb2fd725d41 ("of: Respect #{iommu,msi}-cells in maps"):
iommu-map has 1-cell entries targeting 2-cell #iommu-cells, treating as 1-cell output
So fix the entries to match the provider's '#iommu-cells' property.
--- arch/arm64/boot/dts/qcom/sm8250.dtsi | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
arch/arm64/boot/dts/qcom/sm8250.dtsi +6 -6
@@ -2187,8 +2187,8 @@ pcie0: pcie@1c00000 { "tbu", "ddrss_sf_tbu"; - iommu-map = <0x0 &apps_smmu 0x1c00 0x1>, - <0x100 &apps_smmu 0x1c01 0x1>; + iommu-map = <0x0 &apps_smmu 0x1c00 0x0 0x1>, + <0x100 &apps_smmu 0x1c01 0x0 0x1>; resets = <&gcc GCC_PCIE_0_BCR>; reset-names = "pci";
@@ -2312,8 +2312,8 @@ pcie1: pcie@1c08000 { assigned-clocks = <&gcc GCC_PCIE_1_AUX_CLK>; assigned-clock-rates = <19200000>; - iommu-map = <0x0 &apps_smmu 0x1c80 0x1>, - <0x100 &apps_smmu 0x1c81 0x1>; + iommu-map = <0x0 &apps_smmu 0x1c80 0x0 0x1>, + <0x100 &apps_smmu 0x1c81 0x0 0x1>; resets = <&gcc GCC_PCIE_1_BCR>; reset-names = "pci";
@@ -2437,8 +2437,8 @@ pcie2: pcie@1c10000 { assigned-clocks = <&gcc GCC_PCIE_2_AUX_CLK>; assigned-clock-rates = <19200000>; - iommu-map = <0x0 &apps_smmu 0x1d00 0x1>, - <0x100 &apps_smmu 0x1d01 0x1>; + iommu-map = <0x0 &apps_smmu 0x1d00 0x0 0x1>, + <0x100 &apps_smmu 0x1d01 0x0 0x1>; resets = <&gcc GCC_PCIE_2_BCR>; reset-names = "pci";
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 770/1376 arm64: dts: qcom: sm8350: Fix the PCIe iommu-map entries
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <[email protected]>
[ Upstream commit 80337ea3a154230621c0b4e3c831f5d81712ba18 ]
The IOMMU provider apps_smmu uses '#iommu-cells = <2>', but the PCIe iommu-map entries specify only one cell for the SID, omitting the SID mask. This went unnoticed until the OF core started warning with commit ccb2fd725d41 ("of: Respect #{iommu,msi}-cells in maps"):
iommu-map has 1-cell entries targeting 2-cell #iommu-cells, treating as 1-cell output
So fix the entries to match the provider's '#iommu-cells' property.
--- arch/arm64/boot/dts/qcom/sm8350.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
arch/arm64/boot/dts/qcom/sm8350.dtsi +4 -4
@@ -1571,8 +1571,8 @@ pcie0: pcie@1c00000 { "aggre1", "aggre0"; - iommu-map = <0x0 &apps_smmu 0x1c00 0x1>, - <0x100 &apps_smmu 0x1c01 0x1>; + iommu-map = <0x0 &apps_smmu 0x1c00 0x0 0x1>, + <0x100 &apps_smmu 0x1c01 0x0 0x1>; resets = <&gcc GCC_PCIE_0_BCR>; reset-names = "pci";
@@ -1678,8 +1678,8 @@ pcie1: pcie@1c08000 { "ddrss_sf_tbu", "aggre1"; - iommu-map = <0x0 &apps_smmu 0x1c80 0x1>, - <0x100 &apps_smmu 0x1c81 0x1>; + iommu-map = <0x0 &apps_smmu 0x1c80 0x0 0x1>, + <0x100 &apps_smmu 0x1c81 0x0 0x1>; resets = <&gcc GCC_PCIE_1_BCR>; reset-names = "pci";
Signature · 1 line
2.53.0
Re: [PATCH 6.12 0770/1376] arm64: dts: qcom: sm8350: Fix the PCIe iommu-map entries
Quoted 17 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <[email protected]>
[ Upstream commit
80337ea3a154230621c0b4e3c831f5d81712ba18]The IOMMU provider
apps_smmuuses '#iommu-cells = <2>', but the PCIe iommu-map entries specify only one cell for the SID, omitting the SID mask. This went unnoticed until the OF core started warning with commitccb2fd725d41("of: Respect #{iommu,msi}-cells in maps"):iommu-map has 1-cell entries targeting 2-cell #iommu-cells, treating as 1-cell output
So fix the entries to match the provider's '#iommu-cells' property.
Quoted 8 lines
Fixes 6daee40678a0 ("arm64: dts: qcom: sm8350: add PCIe devices")Signed-off-by Manivannan Sadhasivam <[email protected]>Reviewed-by Konrad Dybcio <[email protected]>Reviewed-by Dmitry Baryshkov <[email protected]>Signed-off-by Bjorn Andersson <[email protected]>Signed-off-by Sasha Levin <[email protected]>---
Hi Greg/Sasha,
I ran an AI-assisted backport review, and I have verified the report. It looks valid to me.
The SM8350 change creates two five-cell iommu-map records per controller. The 6.12 OF parser still accepts only fixed four-cell records, so each 40-byte property fails its 16-byte record-length check before translation. PCI setup can then proceed without the expected IOMMU attachment.
Upstream relies on ccb2fd725d411265df8f7ce12a66c226b16014e6 and its OF
API preparation. Since that broader parser series is absent, Maybe we should revert this isolated DTS backport and retaining the working legacy form.
Thoughts?
thnaks,
Harshit> arch/arm64/boot/dts/qcom/sm8350.dtsi | 8 ++++----
Quoted 28 lines
1 file changed, 4 insertions(+), 4 deletions(-)arch/arm64/boot/dts/qcom/sm8350.dtsi +4
-4@@ -1571,8 +1571,8 @@ pcie0: pcie@1c00000 { "aggre1", "aggre0"; - iommu-map = <0x0 &apps_smmu 0x1c00 0x1>, - <0x100 &apps_smmu 0x1c01 0x1>; + iommu-map = <0x0 &apps_smmu 0x1c00 0x0 0x1>, + <0x100 &apps_smmu 0x1c01 0x0 0x1>; resets = <&gcc GCC_PCIE_0_BCR>; reset-names = "pci";@@ -1678,8 +1678,8 @@ pcie1: pcie@1c08000 { "ddrss_sf_tbu", "aggre1"; - iommu-map = <0x0 &apps_smmu 0x1c80 0x1>, - <0x100 &apps_smmu 0x1c81 0x1>; + iommu-map = <0x0 &apps_smmu 0x1c80 0x0 0x1>, + <0x100 &apps_smmu 0x1c81 0x0 0x1>; resets = <&gcc GCC_PCIE_1_BCR>; reset-names = "pci";
Greg Kroah-Hartman
maintainerPATCH 771/1376 arm64: dts: qcom: sm8450: Fix the PCIe iommu-map entries
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <[email protected]>
[ Upstream commit 9b10e56647fa8f7ab62c7e45ebf4b168f7befa7f ]
The IOMMU provider apps_smmu uses '#iommu-cells = <2>', but the PCIe iommu-map entries specify only one cell for the SID, omitting the SID mask. This went unnoticed until the OF core started warning with commit ccb2fd725d41 ("of: Respect #{iommu,msi}-cells in maps"):
iommu-map has 1-cell entries targeting 2-cell #iommu-cells, treating as 1-cell output
So fix the entries to match the provider's '#iommu-cells' property.
--- arch/arm64/boot/dts/qcom/sm8450.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
arch/arm64/boot/dts/qcom/sm8450.dtsi +4 -4
@@ -1834,8 +1834,8 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, "aggre0", "aggre1"; - iommu-map = <0x0 &apps_smmu 0x1c00 0x1>, - <0x100 &apps_smmu 0x1c01 0x1>; + iommu-map = <0x0 &apps_smmu 0x1c00 0x0 0x1>, + <0x100 &apps_smmu 0x1c01 0x0 0x1>; resets = <&gcc GCC_PCIE_0_BCR>; reset-names = "pci";
@@ -1994,8 +1994,8 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, "ddrss_sf_tbu", "aggre1"; - iommu-map = <0x0 &apps_smmu 0x1c80 0x1>, - <0x100 &apps_smmu 0x1c81 0x1>; + iommu-map = <0x0 &apps_smmu 0x1c80 0x0 0x1>, + <0x100 &apps_smmu 0x1c81 0x0 0x1>; resets = <&gcc GCC_PCIE_1_BCR>; reset-names = "pci";
Signature · 1 line
2.53.0
Re: [PATCH 6.12 0771/1376] arm64: dts: qcom: sm8450: Fix the PCIe iommu-map entries
Quoted 17 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <[email protected]>
[ Upstream commit
9b10e56647fa8f7ab62c7e45ebf4b168f7befa7f]The IOMMU provider
apps_smmuuses '#iommu-cells = <2>', but the PCIe iommu-map entries specify only one cell for the SID, omitting the SID mask. This went unnoticed until the OF core started warning with commitccb2fd725d41("of: Respect #{iommu,msi}-cells in maps"):iommu-map has 1-cell entries targeting 2-cell #iommu-cells, treating as 1-cell output
So fix the entries to match the provider's '#iommu-cells' property.
Quoted 7 lines
Fixes 7b09b1b47335 ("arm64: dts: qcom: sm8450: add PCIe0 RC device")Signed-off-by Manivannan Sadhasivam <[email protected]>Reviewed-by Konrad Dybcio <[email protected]>Reviewed-by Dmitry Baryshkov <[email protected]>Signed-off-by Bjorn Andersson <[email protected]>Signed-off-by Sasha Levin <[email protected]>
Hi Greg/Sasha,
I ran an AI-assisted backport review, and I have verified the report. It looks valid to me.
The SM8450 DTS now supplies two five-cell iommu-map entries per controller, but the 6.12 parser supports only fixed four-cell entries. The resulting 40-byte properties are rejected before requester-ID lookup, and device setup can continue without the intended IOMMU association.
Upstream first took f71f07bee9b56b94f7828cf3082ea19ec590de36 and ccb2fd725d411265df8f7ce12a66c226b16014e6. Since that wider OF/IOMMU series is absent from 6.12.
Maybe we should be dropping this ?
thanks,
Harshit> ---
Quoted 29 lines
arch/arm64/boot/dts/qcom/sm8450.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)arch/arm64/boot/dts/qcom/sm8450.dtsi +4
-4@@ -1834,8 +1834,8 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, "aggre0", "aggre1"; - iommu-map = <0x0 &apps_smmu 0x1c00 0x1>, - <0x100 &apps_smmu 0x1c01 0x1>; + iommu-map = <0x0 &apps_smmu 0x1c00 0x0 0x1>, + <0x100 &apps_smmu 0x1c01 0x0 0x1>; resets = <&gcc GCC_PCIE_0_BCR>; reset-names = "pci";@@ -1994,8 +1994,8 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, "ddrss_sf_tbu", "aggre1"; - iommu-map = <0x0 &apps_smmu 0x1c80 0x1>, - <0x100 &apps_smmu 0x1c81 0x1>; + iommu-map = <0x0 &apps_smmu 0x1c80 0x0 0x1>, + <0x100 &apps_smmu 0x1c81 0x0 0x1>; resets = <&gcc GCC_PCIE_1_BCR>; reset-names = "pci";
Greg Kroah-Hartman
maintainerPATCH 772/1376 arm64: dts: qcom: sm8550: Fix the PCIe iommu-map entries
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <[email protected]>
[ Upstream commit 16d98ee918d63018eaa6cc260791b71319aa4faa ]
The IOMMU provider apps_smmu uses '#iommu-cells = <2>', but the PCIe iommu-map entries specify only one cell for the SID, omitting the SID mask. This went unnoticed until the OF core started warning with commit ccb2fd725d41 ("of: Respect #{iommu,msi}-cells in maps"):
iommu-map has 1-cell entries targeting 2-cell #iommu-cells, treating as 1-cell output
So fix the entries to match the provider's '#iommu-cells' property.
--- arch/arm64/boot/dts/qcom/sm8550.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
arch/arm64/boot/dts/qcom/sm8550.dtsi +4 -4
@@ -1771,8 +1771,8 @@ pcie0: pcie@1c00000 { msi-map = <0x0 &gic_its 0x1400 0x1>, <0x100 &gic_its 0x1401 0x1>; - iommu-map = <0x0 &apps_smmu 0x1400 0x1>, - <0x100 &apps_smmu 0x1401 0x1>; + iommu-map = <0x0 &apps_smmu 0x1400 0x0 0x1>, + <0x100 &apps_smmu 0x1401 0x0 0x1>; resets = <&gcc GCC_PCIE_0_BCR>; reset-names = "pci";
@@ -1892,8 +1892,8 @@ pcie1: pcie@1c08000 { msi-map = <0x0 &gic_its 0x1480 0x1>, <0x100 &gic_its 0x1481 0x1>; - iommu-map = <0x0 &apps_smmu 0x1480 0x1>, - <0x100 &apps_smmu 0x1481 0x1>; + iommu-map = <0x0 &apps_smmu 0x1480 0x0 0x1>, + <0x100 &apps_smmu 0x1481 0x0 0x1>; resets = <&gcc GCC_PCIE_1_BCR>, <&gcc GCC_PCIE_1_LINK_DOWN_BCR>;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 773/1376 arm64: dts: qcom: sm8650: add OPP table support to PCIe
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Neil Armstrong <[email protected]>
[ Upstream commit 5cddecc3d1dce1e20bb64364cb6cd5d8edf376b3 ]
The PCIe bus interconnect path can be scaled depending on the PCIe link established, add the OPP table with all the possible link speeds and the associated power domain level.
Stable-dep-of: 8ccba7b44609 ("arm64: dts: qcom: sm8650: Fix the PCIe iommu-map entries")
--- arch/arm64/boot/dts/qcom/sm8650.dtsi | 89 ++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+)
arch/arm64/boot/dts/qcom/sm8650.dtsi +89 -0
@@ -2279,6 +2279,8 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, power-domains = <&gcc PCIE_0_GDSC>; + operating-points-v2 = <&pcie0_opp_table>; + iommu-map = <0 &apps_smmu 0x1400 0x1>, <0x100 &apps_smmu 0x1401 0x1>;
@@ -2309,6 +2311,45 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, status = "disabled"; + pcie0_opp_table: opp-table { + compatible = "operating-points-v2"; + + /* GEN 1 x1 */ + opp-2500000 { + opp-hz = /bits/ 64 <2500000>; + required-opps = <&rpmhpd_opp_low_svs>; + opp-peak-kBps = <250000 1>; + }; + + /* GEN 1 x2 and GEN 2 x1 */ + opp-5000000 { + opp-hz = /bits/ 64 <5000000>; + required-opps = <&rpmhpd_opp_low_svs>; + opp-peak-kBps = <500000 1>; + }; + + /* GEN 2 x2 */ + opp-10000000 { + opp-hz = /bits/ 64 <10000000>; + required-opps = <&rpmhpd_opp_low_svs>; + opp-peak-kBps = <1000000 1>; + }; + + /* GEN 3 x1 */ + opp-8000000 { + opp-hz = /bits/ 64 <8000000>; + required-opps = <&rpmhpd_opp_nom>; + opp-peak-kBps = <984500 1>; + }; + + /* GEN 3 x2 */ + opp-16000000 { + opp-hz = /bits/ 64 <16000000>; + required-opps = <&rpmhpd_opp_nom>; + opp-peak-kBps = <1969000 1>; + }; + }; + pcieport0: pcie@0 { device_type = "pci"; reg = <0x0 0x0 0x0 0x0 0x0>;
@@ -2416,6 +2457,8 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, power-domains = <&gcc PCIE_1_GDSC>; + operating-points-v2 = <&pcie1_opp_table>; + iommu-map = <0 &apps_smmu 0x1480 0x1>, <0x100 &apps_smmu 0x1481 0x1>;
@@ -2446,6 +2489,52 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, status = "disabled"; + pcie1_opp_table: opp-table { + compatible = "operating-points-v2"; + + /* GEN 1 x1 */ + opp-2500000 { + opp-hz = /bits/ 64 <2500000>; + required-opps = <&rpmhpd_opp_low_svs>; + opp-peak-kBps = <250000 1>; + }; + + /* GEN 1 x2 and GEN 2 x1 */ + opp-5000000 { + opp-hz = /bits/ 64 <5000000>; + required-opps = <&rpmhpd_opp_low_svs>; + opp-peak-kBps = <500000 1>; + }; + + /* GEN 2 x2 */ + opp-10000000 { + opp-hz = /bits/ 64 <10000000>; + required-opps = <&rpmhpd_opp_low_svs>; + opp-peak-kBps = <1000000 1>; + }; + + /* GEN 3 x1 */ + opp-8000000 { + opp-hz = /bits/ 64 <8000000>; + required-opps = <&rpmhpd_opp_nom>; + opp-peak-kBps = <984500 1>; + }; + + /* GEN 3 x2 and GEN 4 x1 */ + opp-16000000 { + opp-hz = /bits/ 64 <16000000>; + required-opps = <&rpmhpd_opp_nom>; + opp-peak-kBps = <1969000 1>; + }; + + /* GEN 4 x2 */ + opp-32000000 { + opp-hz = /bits/ 64 <32000000>; + required-opps = <&rpmhpd_opp_nom>; + opp-peak-kBps = <3938000 1>; + }; + }; + pcie@0 { device_type = "pci"; reg = <0x0 0x0 0x0 0x0 0x0>;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 774/1376 arm64: dts: qcom: sm8650: Fix the PCIe iommu-map entries
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <[email protected]>
[ Upstream commit 8ccba7b44609d58db088447a771f6f30cfa8739e ]
The IOMMU provider apps_smmu uses '#iommu-cells = <2>', but the PCIe iommu-map entries specify only one cell for the SID, omitting the SID mask. This went unnoticed until the OF core started warning with commit ccb2fd725d41 ("of: Respect #{iommu,msi}-cells in maps"):
iommu-map has 1-cell entries targeting 2-cell #iommu-cells, treating as 1-cell output
So fix the entries to match the provider's '#iommu-cells' property.
--- arch/arm64/boot/dts/qcom/sm8650.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
arch/arm64/boot/dts/qcom/sm8650.dtsi +4 -4
@@ -2281,8 +2281,8 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, operating-points-v2 = <&pcie0_opp_table>; - iommu-map = <0 &apps_smmu 0x1400 0x1>, - <0x100 &apps_smmu 0x1401 0x1>; + iommu-map = <0 &apps_smmu 0x1400 0x0 0x1>, + <0x100 &apps_smmu 0x1401 0x0 0x1>; interrupt-map = <0 0 0 1 &intc 0 0 0 149 IRQ_TYPE_LEVEL_HIGH>, <0 0 0 2 &intc 0 0 0 150 IRQ_TYPE_LEVEL_HIGH>,
@@ -2459,8 +2459,8 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, operating-points-v2 = <&pcie1_opp_table>; - iommu-map = <0 &apps_smmu 0x1480 0x1>, - <0x100 &apps_smmu 0x1481 0x1>; + iommu-map = <0 &apps_smmu 0x1480 0x0 0x1>, + <0x100 &apps_smmu 0x1481 0x0 0x1>; interrupt-map = <0 0 0 1 &intc 0 0 0 434 IRQ_TYPE_LEVEL_HIGH>, <0 0 0 2 &intc 0 0 0 435 IRQ_TYPE_LEVEL_HIGH>,
Signature · 1 line
2.53.0
Re: [PATCH 6.12 0774/1376] arm64: dts: qcom: sm8650: Fix the PCIe iommu-map entries
Quoted 34 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <[email protected]>
[ Upstream commit
8ccba7b44609d58db088447a771f6f30cfa8739e]The IOMMU provider
apps_smmuuses '#iommu-cells = <2>', but the PCIe iommu-map entries specify only one cell for the SID, omitting the SID mask. This went unnoticed until the OF core started warning with commitccb2fd725d41("of: Respect #{iommu,msi}-cells in maps"):iommu-map has 1-cell entries targeting 2-cell #iommu-cells, treating as 1-cell output
So fix the entries to match the provider's '#iommu-cells' property.
Fixes 10e024671295 ("arm64: dts: qcom: sm8650: add interconnect dependent device nodes")Signed-off-by Manivannan Sadhasivam <[email protected]>Reviewed-by Neil Armstrong <[email protected]>Reviewed-by Konrad Dybcio <[email protected]>Reviewed-by Dmitry Baryshkov <[email protected]>Signed-off-by Bjorn Andersson <[email protected]>Signed-off-by Sasha Levin <[email protected]>--- arch/arm64/boot/dts/qcom/sm8650.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)arch/arm64/boot/dts/qcom/sm8650.dtsi +0
-0
arch/arm64/boot/dts/qcom/sm8650.dtsi &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, · line 2285
Quoted 7 lines
arch/arm64/boot/dts/qcom/sm8650.dtsi +2
-2@@ -2281,8 +2281,8 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, operating-points-v2 = <&pcie0_opp_table>; - iommu-map = <0 &apps_smmu 0x1400 0x1>, - <0x100 &apps_smmu 0x1401 0x1>; + iommu-map = <0 &apps_smmu 0x1400 0x0 0x1>, + <0x100 &apps_smmu 0x1401 0x0 0x1>;
Hi Greg/Sasha,
I ran an AI-assisted backport review, and I have verified the report. It looks valid to me.
The SM8650 DTS now has two five-cell iommu-map records per controller, but 6.12's of_map_id() only accepts fixed four-cell records. Each 40-byte map fails its 16-byte record-length check before requester-ID translation, and PCI setup can continue without the intended IOMMU association.
Upstream relies on ccb2fd725d411265df8f7ce12a66c226b16014e6 plus its OF API prerequisites. Since that broader series is absent, Thoughts?
In v6.12.110, the same missing OF-parser dependency affects all eight neighboring QCOM fixes: sc8180x, sdm845, sm8150, sm8250, sm8350, sm8450, sm8550, and sm8650.
maybe we should revert all of these ?
thanks,
Harshit>
Quoted 13 lines
arch/arm64/boot/dts/qcom/sm8650.dtsi +2
-2interrupt-map = <0 0 0 1 &intc 0 0 0 149 IRQ_TYPE_LEVEL_HIGH>, <0 0 0 2 &intc 0 0 0 150 IRQ_TYPE_LEVEL_HIGH>,@@ -2459,8 +2459,8 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, operating-points-v2 = <&pcie1_opp_table>; - iommu-map = <0 &apps_smmu 0x1480 0x1>, - <0x100 &apps_smmu 0x1481 0x1>; + iommu-map = <0 &apps_smmu 0x1480 0x0 0x1>, + <0x100 &apps_smmu 0x1481 0x0 0x1>; interrupt-map = <0 0 0 1 &intc 0 0 0 434 IRQ_TYPE_LEVEL_HIGH>, <0 0 0 2 &intc 0 0 0 435 IRQ_TYPE_LEVEL_HIGH>,
Greg Kroah-Hartman
maintainerPATCH 775/1376 power: supply: isp1704_charger: cancel work on remove
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hongyan Xu <[email protected]>
[ Upstream commit 60c5b8a9ef4dbc5d69bbc1a960fe55826cb3b643 ]
The USB notifier and initial VBUS detection can schedule isp->work. The remove path unregisters the notifier and power supply, but does not wait for queued or running work before tearing down the power supply state.
Cancel the work after unregistering the notifier. Do this before unregistering the power supply.
This issue was found by a static analysis tool.
--- drivers/power/supply/isp1704_charger.c | 1 + 1 file changed, 1 insertion(+)
drivers/power/supply/isp1704_charger.c +1 -0
@@ -482,6 +482,7 @@ static void isp1704_charger_remove(struct platform_device *pdev)struct isp1704_charger *isp =platform_get_drvdata (pdev);usb_unregister_notifier (isp->phy, &isp->nb); +cancel_work_sync (&isp->work);power_supply_unregister (isp->psy);isp1704_charger_set_power (isp,0 ); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 776/1376 power: supply: sc2731_charger: cancel work on remove
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hongyan Xu <[email protected]>
[ Upstream commit dfc859bb8d332c525872f1a44028137724fa1998 ]
The USB notifier and initial charger detection can schedule info->work. The remove path unregisters the notifier, but does not cancel queued or running work before the devm-allocated driver data is released.
Set the platform drvdata used by remove, then cancel the work after unregistering the notifier.
This issue was found by a static analysis tool.
--- drivers/power/supply/sc2731_charger.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/power/supply/sc2731_charger.c +2 -0
@@ -466,6 +466,7 @@ static int sc2731_charger_probe(struct platform_device *pdev)mutex_init (&info->lock); info->dev = &pdev->dev;INIT_WORK (&info->work, sc2731_charger_work); +platform_set_drvdata (pdev, info); info->regmap =dev_get_regmap (pdev->dev.parent,NULL );if (!info->regmap) {
@@ -516,6 +517,7 @@ static void sc2731_charger_remove(struct platform_device *pdev)struct sc2731_charger_info *info =platform_get_drvdata (pdev);usb_unregister_notifier (info->usb_phy, &info->usb_notify); +cancel_work_sync (&info->work); }static const struct of_device_id sc2731_charger_of_match[] = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 777/1376 bpf: Fix potential UAF in bpf_netns_link_update_prog
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pu Lehui <[email protected]>
[ Upstream commit 5c5997836381010fc5907b36bc17d3b19407e933 ]
In bpf_netns_link_update_prog, the checks for old_prog and prog type are currently performed locklessly before acquiring netns_bpf_mutex. This creates a race condition that can lead to a UAF issue.
If two threads concurrently execute BPF_LINK_UPDATE on the same netns link, the following execution path can trigger a UAF:
CPU0 CPU1bpf_netns_link_update_prog
if (old_prog && old_prog != link->prog)
return -EPERM;
bpf_netns_link_update_prog
if (old_prog && old_prog != link->prog)
...
old_prog = xchg(&link->prog, new_prog);
bpf_prog_put(old_prog); if (new_prog->type != link->prog->type) <-- trigger UAF
Fix this by moving the old_prog and prog->type checks inside the netns_bpf_mutex critical section. Meanwhile, use guard() to simplify lock management and avoid all the goto jumping.
--- kernel/bpf/net_namespace.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-)
kernel/bpf/net_namespace.c +6 -11
@@ -172,33 +172,28 @@ static int bpf_netns_link_update_prog(struct bpf_link *link,struct net *net;int idx, ret; +guard (mutex)(&netns_bpf_mutex); +if (old_prog && old_prog != link->prog)return -EPERM ;if (new_prog->type != link->prog->type)return -EINVAL ; -mutex_lock (&netns_bpf_mutex); - net = net_link->net; -if (!net || !check_net (net)) { +if (!net || !check_net (net))/* Link auto-detached or netns dying */ - ret = -ENOLINK ; - goto out_unlock; - } +return -ENOLINK ; run_array =rcu_dereference_protected (net->bpf.run_array[type],lockdep_is_held (&netns_bpf_mutex)); idx =link_index (net, type, net_link); ret =bpf_prog_array_update_at (run_array, idx, new_prog);if (ret) - goto out_unlock; +return ret; old_prog =xchg (&link->prog, new_prog);bpf_prog_put (old_prog); - -out_unlock: -mutex_unlock (&netns_bpf_mutex); -return ret; +return 0 ; } static int bpf_netns_link_fill_info(const struct bpf_link *link,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 778/1376 bpf: Fix potential UAF when reading bpf link info
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pu Lehui <[email protected]>
[ Upstream commit 863f3ddd0b8ac65abfb50d3be0869268ac0e277b ]
In bpf_link_show_fdinfo and bpf_link_get_info_by_fd, link->prog is accessed without holding any locks. If the prog is concurrently replaced via bpf_link_update, the old prog can be freed, leading to a potential UAF issue.
Fix this by accessing link->prog under RCU protection to safely fetch the pointer and guarantee its lifetime while reading its fields.
--- kernel/bpf/syscall.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-)
kernel/bpf/syscall.c +17 -4
@@ -3091,9 +3091,10 @@ static const char *bpf_link_type_strs[] = {static void bpf_link_show_fdinfo (struct seq_file *m,struct file *filp) {const struct bpf_link *link = filp->private_data; -const struct bpf_prog *prog = link->prog; +const struct bpf_prog *prog;enum bpf_link_type type = link->type;char prog_tag[sizeof (prog->tag) *2 +1 ] = { }; +u32 prog_id =0 ;if (type <ARRAY_SIZE (bpf_link_type_strs) && bpf_link_type_strs[type]) {seq_printf (m,"link_type:\t%s\n" , bpf_link_type_strs[type]);
@@ -3103,13 +3104,20 @@ static void bpf_link_show_fdinfo(struct seq_file *m, struct file *filp) }seq_printf (m,"link_id:\t%u\n" , link->id); +rcu_read_lock (); + prog =READ_ONCE (link->prog);if (prog) {bin2hex (prog_tag, prog->tag,sizeof (prog->tag)); + prog_id = prog->aux->id; + } +rcu_read_unlock (); + +if (prog) {seq_printf (m,"prog_tag:\t%s\n" "prog_id:\t%u\n" , prog_tag, - prog->aux->id); + prog_id); }if (link->ops->show_fdinfo) link->ops->show_fdinfo (link, m);
@@ -4917,6 +4925,7 @@ static int bpf_link_get_info_by_fd(struct file *file, {struct bpf_link_info __user *uinfo =u64_to_user_ptr (attr->info.info);struct bpf_link_info info; +const struct bpf_prog *prog;u32 info_len = attr->info.info_len;int err;
@@ -4931,8 +4940,12 @@ static int bpf_link_get_info_by_fd(struct file *file, info.type = link->type; info.id = link->id; -if (link->prog) - info.prog_id = link->prog->aux->id; + +rcu_read_lock (); + prog =READ_ONCE (link->prog); +if (prog) + info.prog_id = prog->aux->id; +rcu_read_unlock ();if (link->ops->fill_link_info) { err = link->ops->fill_link_info (link, &info);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 779/1376 lib/test_hmm: fail dmirror_fault() when the mirrored mm is gone
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stanislav Kinsburskii <[email protected]>
[ Upstream commit 6a8024511ddf4877435c34fb3d6028aa8e590649 ]
dmirror_fault() is called from the dmirror_read() and dmirror_write() retry loops after dmirror_do_read() or dmirror_do_write() finds a missing device page table entry.
If the mirrored mm has already exited, mmget_not_zero() fails. The current code returns 0 in that case, which tells the caller that faulting succeeded even though no page was faulted and no device page table entry was installed. The caller then retries the same address, hits -ENOENT again, and can loop forever without making progress.
Return -EFAULT instead, so the ioctl fails when the mirrored mm is no longer faultable.
--- lib/test_hmm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
lib/test_hmm.c +1 -1
@@ -391,7 +391,7 @@ static int dmirror_fault(struct dmirror *dmirror, unsigned long start,/* Since the mm is for the mirrored process, get a reference first. */ if (!mmget_not_zero (mm)) -return 0 ; +return -EFAULT ;for (addr = start; addr < end; addr = range.end) { range.start = addr;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 780/1376 clk: qcom: gpucc-qcm2290: Park RCGs clk source at XO during disable
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Imran Shaik <[email protected]>
[ Upstream commit ab46b5fb668b8b9b848a8f036fc4c06ce86b7e3b ]
The RCG's clk src has to be parked at XO while disabling as per hardware team's recommendation, hence use clk_rcg2_shared_ops to achieve the same.
--- drivers/clk/qcom/gpucc-qcm2290.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/qcom/gpucc-qcm2290.c +1 -1
@@ -144,7 +144,7 @@ static struct clk_rcg2 gpu_cc_gx_gfx3d_clk_src = { .parent_data = gpu_cc_parent_data_1, .num_parents = ARRAY_SIZE(gpu_cc_parent_data_1), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 781/1376 clk: qcom: Return expected ENOMEM error on dynamic allocation failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vladimir Zapolskiy <[email protected]>
[ Upstream commit 22d9257f08913b6eec3e8ece4d13d9c41f14428b ]
If a dynamic memory allocation fails, the returned error code in clock controller driver probe functions on a few legacy platforms should be set to -ENOMEM instead of -EINVAL.
--- drivers/clk/qcom/common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/clk/qcom/common.c +2 -2
@@ -165,7 +165,7 @@ static int _qcom_cc_register_board_clk(struct device *dev, const char *path,if (!node) { fixed =devm_kzalloc (dev,sizeof (*fixed),GFP_KERNEL );if (!fixed) -return -EINVAL ; +return -ENOMEM ; fixed->fixed_rate = rate; fixed->hw.init = &init_data;
@@ -182,7 +182,7 @@ static int _qcom_cc_register_board_clk(struct device *dev, const char *path,if (add_factor) { factor =devm_kzalloc (dev,sizeof (*factor),GFP_KERNEL );if (!factor) -return -EINVAL ; +return -ENOMEM ; factor->mult = factor->div =1 ; factor->hw.init = &init_data;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 782/1376 md/bitmap: resume array on backlog_store() error path
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chen Cheng <[email protected]>
[ Upstream commit 2911cd0a0f4366a7e06832bc5f0a7fdcc138e4dc ]
backlog_store() suspends the array before checking whether a write-mostly device exists. If no such device exists, the error path only unlocks reconfig_mutex and leaves the array suspended, blocking subsequent I/O.
Use mddev_unlock_and_resume() to release both states.
--- drivers/md/md-bitmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/md/md-bitmap.c +1 -1
@@ -2816,7 +2816,7 @@ backlog_store(struct mddev *mddev, const char *buf, size_t len)if (!has_write_mostly) {pr_warn_ratelimited ("%s: can't set backlog, no write mostly device available\n" ,mdname (mddev)); -mddev_unlock (mddev); +mddev_unlock_and_resume (mddev);return -EINVAL ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 783/1376 md: remove unused mddev argument from export_rdev
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chen Cheng <[email protected]>
[ Upstream commit 6f507eb2bb5491327fe634dc23558d4ca5d710b8 ]
The mddev argument in export_rdev() is never used. Remove it to simplify callers.
Stable-dep-of: bace2010dd7a ("md: scope memalloc_noio to allocation critical sections")
--- drivers/md/md.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-)
drivers/md/md.c +14 -14
@@ -105,7 +105,7 @@ struct workqueue_struct *md_bitmap_wq;static int remove_and_add_spares (struct mddev *mddev,struct md_rdev *this);static void mddev_detach (struct mddev *mddev); -static void export_rdev (struct md_rdev *rdev,struct mddev *mddev); +static void export_rdev (struct md_rdev *rdev);static void md_wakeup_thread_directly (struct md_thread __rcu **thread);/*
@@ -865,7 +865,7 @@ void mddev_unlock(struct mddev *mddev)list_for_each_entry_safe (rdev, tmp, &delete, same_set) {list_del_init (&rdev->same_set);kobject_del (&rdev->kobj); -export_rdev (rdev, mddev); +export_rdev (rdev); } }EXPORT_SYMBOL_GPL (mddev_unlock);
@@ -2498,7 +2498,7 @@ void md_autodetect_dev(dev_t dev);/* just for claiming the bdev */ static struct md_rdev claim_rdev; -static void export_rdev (struct md_rdev *rdev,struct mddev *mddev) +static void export_rdev (struct md_rdev *rdev) {pr_debug ("md: export_rdev(%pg)\n" , rdev->bdev);md_rdev_clear (rdev);
@@ -4637,7 +4637,7 @@ new_dev_store(struct mddev *mddev, const char *buf, size_t len) err =bind_rdev_to_array (rdev, mddev); out:if (err) -export_rdev (rdev, mddev); +export_rdev (rdev);mddev_unlock_and_resume (mddev);if (!err)md_new_event ();
@@ -6718,7 +6718,7 @@ static void autorun_devices(int part)rdev_for_each_list (rdev, tmp, &candidates) {list_del_init (&rdev->same_set);if (bind_rdev_to_array (rdev, mddev)) -export_rdev (rdev, mddev); +export_rdev (rdev); }autorun_array (mddev);mddev_unlock_and_resume (mddev);
@@ -6728,7 +6728,7 @@ static void autorun_devices(int part)*/ rdev_for_each_list (rdev, tmp, &candidates) {list_del_init (&rdev->same_set); -export_rdev (rdev, mddev); +export_rdev (rdev); }mddev_put (mddev); }
@@ -6916,13 +6916,13 @@ int md_add_new_disk(struct mddev *mddev, struct mdu_disk_info_s *info)pr_warn ("md: %pg has different UUID to %pg\n" , rdev->bdev, rdev0->bdev); -export_rdev (rdev, mddev); +export_rdev (rdev);return -EINVAL ; } } err =bind_rdev_to_array (rdev, mddev);if (err) -export_rdev (rdev, mddev); +export_rdev (rdev);return err; }
@@ -6965,7 +6965,7 @@ int md_add_new_disk(struct mddev *mddev, struct mdu_disk_info_s *info)/* This was a hot-add request, but events doesn't * match, so reject it. */ -export_rdev (rdev, mddev); +export_rdev (rdev);return -EINVAL ; }
@@ -6991,7 +6991,7 @@ int md_add_new_disk(struct mddev *mddev, struct mdu_disk_info_s *info) } }if (has_journal || mddev->bitmap) { -export_rdev (rdev, mddev); +export_rdev (rdev);return -EBUSY ; }set_bit (Journal, &rdev->flags);
@@ -7006,7 +7006,7 @@ int md_add_new_disk(struct mddev *mddev, struct mdu_disk_info_s *info)/* --add initiated by this node */ err = md_cluster_ops->add_new_disk (mddev, rdev);if (err) { -export_rdev (rdev, mddev); +export_rdev (rdev);return err; } }
@@ -7016,7 +7016,7 @@ int md_add_new_disk(struct mddev *mddev, struct mdu_disk_info_s *info) err =bind_rdev_to_array (rdev, mddev);if (err) -export_rdev (rdev, mddev); +export_rdev (rdev);if (mddev_is_clustered (mddev)) {if (info->state & (1 <<MD_DISK_CANDIDATE )) {
@@ -7079,7 +7079,7 @@ int md_add_new_disk(struct mddev *mddev, struct mdu_disk_info_s *info) err =bind_rdev_to_array (rdev, mddev);if (err) { -export_rdev (rdev, mddev); +export_rdev (rdev);return err; } }
@@ -7192,7 +7192,7 @@ static int hot_add_disk(struct mddev *mddev, dev_t dev)return 0 ; abort_export: -export_rdev (rdev, mddev); +export_rdev (rdev);return err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 784/1376 md: skip redundant raid_disks update when value is unchanged
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abd-Alrhman Masalkhi <[email protected]>
[ Upstream commit abaf4783822851678632e5cea98aa5aead99852f ]
Calling update_raid_disks() with the same value as the current one can trigger unnecessary work. For example, RAID1 will reallocate resources such as the mempool for r1bio.
Stable-dep-of: bace2010dd7a ("md: scope memalloc_noio to allocation critical sections")
--- drivers/md/md.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/md/md.c +4 -3
@@ -4196,9 +4196,10 @@ raid_disks_store(struct mddev *mddev, const char *buf, size_t len) err =mddev_suspend_and_lock (mddev);if (err)return err; -if (mddev->pers) - err =update_raid_disks (mddev, n); -else if (mddev->reshape_position != MaxSector) { +if (mddev->pers) { +if (n != mddev->raid_disks) + err =update_raid_disks (mddev, n); + }else if (mddev->reshape_position != MaxSector) {struct md_rdev *rdev;int olddisks = mddev->raid_disks - mddev->delta_disks;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 785/1376 md: scope memalloc_noio to allocation critical sections
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chen Cheng <[email protected]>
[ Upstream commit bace2010dd7ac07bc980575afb135c406730a7fe ]
Storing a memalloc_noio_save() token in mddev->noio_flags lets one task save the token and another task restore it. With concurrent suspend sysfs writes, task A can enter PF_MEMALLOC_NOIO, return to userspace still in that scope, and later task B can restore A's saved token.
Avoid tying the token lifetime to mddev. Keep mddev_suspend() and mddev_resume() only responsible for array suspension, and enter PF_MEMALLOC_NOIO only in the MD paths that allocate memory after the array has been suspended. Restore the token before resuming the array.
A reproducer repeatedly writes suspend_lo and suspend_hi from concurrent workers and checks each worker's /proc/self/stat flags before and after the sysfs write.
--- drivers/md/md-bitmap.c | 3 +++ drivers/md/md.c | 53 ++++++++++++++++++++++++++++-------------- drivers/md/md.h | 1 - drivers/md/raid5.c | 14 +++++++---- 4 files changed, 48 insertions(+), 23 deletions(-)
drivers/md/md-bitmap.c +3 -0
@@ -2612,10 +2612,12 @@ static ssize_t location_store(struct mddev *mddev, const char *buf, size_t len) { int rv; +unsigned int noio_flags; rv =mddev_suspend_and_lock (mddev);if (rv)return rv; + noio_flags =memalloc_noio_save ();if (mddev->pers) {if (mddev->recovery || mddev->sync_thread) {
@@ -2689,6 +2691,7 @@ location_store(struct mddev *mddev, const char *buf, size_t len) } rv =0 ; out: +memalloc_noio_restore (noio_flags);mddev_unlock_and_resume (mddev);if (rv)return rv;
drivers/md/md.c +36 -17
206 lines not on this page · raw message
drivers/md/md.h +0 -1
@@ -577,7 +577,6 @@ struct mddev {void (*sync_super)(struct mddev *mddev,struct md_rdev *rdev);struct md_cluster_info *cluster_info;unsigned int good_device_nr;/* good device num within cluster raid */ -unsigned int noio_flag;/* for memalloc scope API */ /* * Temporarily store rdev that will be finally removed when
drivers/md/raid5.c +9 -5
@@ -2460,11 +2460,6 @@ static int scribble_alloc(struct raid5_percpu *percpu,sizeof (unsigned int ) * (num +2 );void *scribble; -/* -* If here is in raid array suspend context, it is in memalloc noio -* context as well, there is no potential recursive memory reclaim -* I/Os with the GFP_KERNEL flag. -*/ scribble =kvmalloc_array (cnt, obj_size,GFP_KERNEL );if (!scribble)return -ENOMEM ;
@@ -2479,6 +2474,7 @@ static int scribble_alloc(struct raid5_percpu *percpu,static int resize_chunks (struct r5conf *conf,int new_disks,int new_sectors) {unsigned long cpu; +unsigned int noio_flags;int err =0 ;/* Never shrink. */
@@ -2487,6 +2483,7 @@ static int resize_chunks(struct r5conf *conf, int new_disks, int new_sectors)return 0 ;raid5_quiesce (conf->mddev, true); + noio_flags =memalloc_noio_save ();cpus_read_lock ();for_each_present_cpu (cpu) {
@@ -2500,6 +2497,7 @@ static int resize_chunks(struct r5conf *conf, int new_disks, int new_sectors) }cpus_read_unlock (); +memalloc_noio_restore (noio_flags);raid5_quiesce (conf->mddev, false);if (!err) {
@@ -6990,6 +6988,7 @@ raid5_store_stripe_size(struct mddev *mddev, const char *page, size_t len) {struct r5conf *conf;unsigned long new; +unsigned int noio_flags =0 ;int err;int size;
@@ -7030,6 +7029,7 @@ raid5_store_stripe_size(struct mddev *mddev, const char *page, size_t len) goto out_unlock; } + noio_flags =memalloc_noio_save ();mutex_lock (&conf->cache_size_mutex); size = conf->max_nr_stripes;
@@ -7046,6 +7046,7 @@ raid5_store_stripe_size(struct mddev *mddev, const char *page, size_t len)mutex_unlock (&conf->cache_size_mutex); out_unlock: +memalloc_noio_restore (noio_flags);mddev_unlock_and_resume (mddev);return err ?: len; }
@@ -8912,6 +8913,7 @@ static void *raid6_takeover(struct mddev *mddev)static int raid5_change_consistency_policy (struct mddev *mddev,const char *buf) {struct r5conf *conf; +unsigned int noio_flags;int err; err =mddev_suspend_and_lock (mddev);
@@ -8923,6 +8925,7 @@ static int raid5_change_consistency_policy(struct mddev *mddev, const char *buf)return -ENODEV ; } + noio_flags =memalloc_noio_save ();if (strncmp (buf,"ppl" ,3 ) ==0 ) {/* ppl only works with RAID 5 */ if (!raid5_has_ppl (conf) && conf->level ==5 ) {
@@ -8962,6 +8965,7 @@ static int raid5_change_consistency_policy(struct mddev *mddev, const char *buf)if (!err)md_update_sb (mddev,1 ); +memalloc_noio_restore (noio_flags);mddev_unlock_and_resume (mddev);return err;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 786/1376 iommu/dma: Check atomic pool allocation result directly
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aneesh Kumar K.V (Arm) <[email protected]>
[ Upstream commit af95a0ebc0a0db0762be75f51eadf770bad01aaa ]
The non-blocking, non-coherent allocation path uses dma_alloc_from_pool(), which returns the allocated page and fills cpu_addr only on success.
Do not rely on cpu_addr to detect allocation failure in this path. Check the returned page directly before using it for the IOMMU mapping.
--- drivers/iommu/dma-iommu.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
drivers/iommu/dma-iommu.c +8 -5
@@ -1648,13 +1648,16 @@ void *iommu_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, }if (IS_ENABLED (CONFIG_DMA_DIRECT_REMAP ) && - !gfpflags_allow_blocking (gfp) && !coherent) + !gfpflags_allow_blocking (gfp) && !coherent) { page =dma_alloc_from_pool (dev,PAGE_ALIGN (size), &cpu_addr, - gfp,NULL ); -else + gfp,NULL ); +if (!page) +return NULL ; + }else { cpu_addr =iommu_dma_alloc_pages (dev, size, &page, gfp, attrs); -if (!cpu_addr) -return NULL ; +if (!cpu_addr) +return NULL ; + } *handle =__iommu_dma_map (dev,page_to_phys (page), size, ioprot, dev->coherent_dma_mask);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 787/1376 swiotlb: Preserve allocation virtual address for dynamic pools
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aneesh Kumar K.V (Arm) <[email protected]>
[ Upstream commit 57d29044d0f29a76c6ec0c112c8c7371d5608dc7 ]
swiotlb_alloc_tlb() can allocate from the DMA atomic pool when a decrypted pool is needed from atomic context. With CONFIG_DMA_DIRECT_REMAP, the atomic pool is backed by remapped virtual addresses, which are not the same as the direct-map addresses returned by phys_to_virt().
swiotlb_init_io_tlb_pool() currently reconstructs the pool virtual address from the physical start address. For atomic-pool backed allocations this stores the wrong address in pool->vaddr. Later, swiotlb_free_tlb() passes that address to dma_free_from_pool(), which will fail to recognize the chunk
Pass the virtual address returned by the allocation path into swiotlb_init_io_tlb_pool(), and store that address in pool->vaddr. This keeps the pool free path using the same virtual address as the allocator.
--- kernel/dma/swiotlb.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-)
kernel/dma/swiotlb.c +19 -12
@@ -268,9 +268,9 @@ void __init swiotlb_update_mem_attributes(void) }static void swiotlb_init_io_tlb_pool (struct io_tlb_pool *mem,phys_addr_t start, -unsigned long nslabs,bool late_alloc,unsigned int nareas) +void *vaddr,unsigned long nslabs,bool late_alloc, +unsigned int nareas) { -void *vaddr =phys_to_virt (start);unsigned long bytes = nslabs <<IO_TLB_SHIFT , i; mem->nslabs = nslabs;
@@ -411,7 +411,7 @@ void __init swiotlb_init_remap(bool addressing_limit, unsigned int flags,return ; } -swiotlb_init_io_tlb_pool (mem,__pa (tlb), nslabs, false, nareas); +swiotlb_init_io_tlb_pool (mem,__pa (tlb), tlb, nslabs, false, nareas);add_mem_pool (&io_tlb_default_mem, mem);if (flags &SWIOTLB_VERBOSE )
@@ -509,7 +509,7 @@ int swiotlb_init_late(size_t size, gfp_t gfp_mask,set_memory_decrypted ((unsigned long )vstart, (nslabs <<IO_TLB_SHIFT ) >>PAGE_SHIFT ); -swiotlb_init_io_tlb_pool (mem,virt_to_phys (vstart), nslabs, true, +swiotlb_init_io_tlb_pool (mem,virt_to_phys (vstart), vstart, nslabs, true, nareas);add_mem_pool (&io_tlb_default_mem, mem);
@@ -607,25 +607,26 @@ static struct page *alloc_dma_pages(gfp_t gfp, size_t bytes, u64 phys_limit)* @bytes: Size of the buffer. * @phys_limit: Maximum allowed physical address of the buffer. * @gfp: GFP flags for the allocation. +* @vaddr: Receives the virtual address for the allocated buffer. * * Return: Allocated pages, or %NULL on allocation failure. */ static struct page *swiotlb_alloc_tlb (struct device *dev,size_t bytes, -u64 phys_limit,gfp_t gfp) +u64 phys_limit,gfp_t gfp,void **vaddr) {struct page *page; + *vaddr =NULL ; +/* * Allocate from the atomic pools if memory is encrypted and * the allocation is atomic, because decrypting may block. */ if (!gfpflags_allow_blocking (gfp) && dev &&force_dma_unencrypted (dev)) { -void *vaddr; -if (!IS_ENABLED (CONFIG_DMA_COHERENT_POOL ))return NULL ; -return dma_alloc_from_pool (dev, bytes, &vaddr, gfp, +return dma_alloc_from_pool (dev, bytes, vaddr, gfp, dma_coherent_ok); }
@@ -647,6 +648,8 @@ static struct page *swiotlb_alloc_tlb(struct device *dev, size_t bytes,return NULL ; } +if (page) + *vaddr =phys_to_virt (page_to_phys (page));return page; }
@@ -687,6 +690,7 @@ static struct io_tlb_pool *swiotlb_alloc_pool(struct device *dev, {struct io_tlb_pool *pool;unsigned int slot_order; +void *tlb_vaddr;struct page *tlb;size_t pool_size;size_t tlb_size;
@@ -703,7 +707,8 @@ static struct io_tlb_pool *swiotlb_alloc_pool(struct device *dev, pool->areas = (void *)pool +sizeof (*pool); tlb_size = nslabs <<IO_TLB_SHIFT ; -while (!(tlb =swiotlb_alloc_tlb (dev, tlb_size, phys_limit, gfp))) { +while (!(tlb =swiotlb_alloc_tlb (dev, tlb_size, phys_limit, gfp, + &tlb_vaddr))) {if (nslabs <= minslabs) goto error_tlb; nslabs =ALIGN (nslabs >>1 ,IO_TLB_SEGSIZE );
@@ -717,11 +722,12 @@ static struct io_tlb_pool *swiotlb_alloc_pool(struct device *dev,if (!pool->slots) goto error_slots; -swiotlb_init_io_tlb_pool (pool,page_to_phys (tlb), nslabs, true, nareas); +swiotlb_init_io_tlb_pool (pool,page_to_phys (tlb), tlb_vaddr, nslabs, + true, nareas);return pool; error_slots: -swiotlb_free_tlb (page_address (tlb), tlb_size); +swiotlb_free_tlb (tlb_vaddr, tlb_size); error_tlb:kfree (pool); error:
@@ -1849,7 +1855,8 @@ static int rmem_swiotlb_device_init(struct reserved_mem *rmem,set_memory_decrypted ((unsigned long )phys_to_virt (rmem->base), rmem->size >>PAGE_SHIFT ); -swiotlb_init_io_tlb_pool (pool, rmem->base, nslabs, +swiotlb_init_io_tlb_pool (pool, rmem->base,phys_to_virt (rmem->base), + nslabs, false, nareas); mem->force_bounce = true; mem->for_alloc = true;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 788/1376 i3c: dw: avoid shift-out-of-bounds when DAA assigns no devices
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jakub Kicinski <[email protected]>
[ Upstream commit 038cf48b3170af26a70bf2dee4f8c3ac910f5176 ]
On an empty bus ENTDAA assigns nothing, so cmd->rx_len (the count of addresses left unassigned) equals master->maxdevs.
The GENMASK() index master->maxdevs - cmd->rx_len - 1 then becomes -1, which trips up UBSAN. This happens every time on boot on a Gigabyte/AMD server:
UBSAN: shift-out-of-bounds in drivers/i3c/master/dw-i3c-master.c:905:12
shift exponent 64 is too large for 64-bit type 'long unsigned int'
CPU: 7 UID: 0 PID: 963 Comm: (udev-worker) Not tainted 7.0.11-200.fc44.x86_64 #1 PREEMPT(lazy)
Hardware name: Giga Computing E163-Z34-AAH1-000/MZ33-DC1-000, BIOS R32_F45 04/01/2026
Call Trace:
<TASK>
dump_stack_lvl+0x5d/0x80
ubsan_epilogue+0x5/0x2b
__ubsan_handle_shift_out_of_bounds.cold+0xd7/0x1ab
dw_i3c_master_daa.cold+0x1b/0x96 [dw_i3c_master]
i3c_master_do_daa_ext.part.0+0x3e/0xf0 [i3c]Skip the mask when no new device was assigned.
--- drivers/i3c/master/dw-i3c-master.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
drivers/i3c/master/dw-i3c-master.c +9 -1
@@ -889,7 +889,15 @@ static int dw_i3c_master_daa(struct i3c_master_controller *m)if (!wait_for_completion_timeout (&xfer->comp,XFER_TIMEOUT ))dw_i3c_master_dequeue_xfer (master, xfer); - newdevs =GENMASK (master->maxdevs - cmd->rx_len -1 ,0 ); +/* +* cmd->rx_len holds the number of addresses ENTDAA left unassigned. +* On an empty bus rx_len == maxdevs, so avoid GENMASK(-1, 0). +*/ +if (cmd->rx_len >= master->maxdevs) + newdevs =0 ; +else + newdevs =GENMASK (master->maxdevs - cmd->rx_len -1 ,0 ); + newdevs &= ~olddevs;for (pos =0 ; pos < master->maxdevs; pos++) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 789/1376 i3c: master: Fix device_register() error path
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adrian Hunter <[email protected]>
[ Upstream commit 74be657d98a8d684c0475f3cbd450ef2a30ffc73 ]
When device_register() fails in i3c_master_register_new_i3c_devs(), put_device() is called to drop the reference taken by device_register(). That drops the last reference, so the device's release callback i3c_device_release() runs and frees the i3c_device.
Two problems follow from that:
i3c_device_release() does WARN_ON(i3cdev->desc), so it warns because desc->dev->desc still points back at the descriptor. Clear it before calling put_device().
After put_device() frees the i3c_device, desc->dev is left pointing at freed memory, so clear desc->dev as well. That prevents, for example, i3c_master_unregister_i3c_devs() seeing desc->dev as non-NULL and dereferencing it.
--- drivers/i3c/master.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/i3c/master.c +2 -0
@@ -1689,7 +1689,9 @@ i3c_master_register_new_i3c_devs(struct i3c_master_controller *master)if (ret) {dev_err (&master->dev,"Failed to add I3C device (err = %d)\n" , ret); + desc->dev->desc =NULL ;put_device (&desc->dev->dev); + desc->dev =NULL ; } } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 790/1376 md: merge mddev has_superblock into mddev_flags
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yu Kuai <[email protected]>
[ Upstream commit fba4a980403d2f489bc680dbff7d7d2514e669f9 ]
There is not need to use a separate field in struct mddev, there are no functional changes.
Stable-dep-of: 140234b2380f ("md/raid1: create serial pool adding rdev to array with serialize_policy=1")
--- drivers/md/md.c | 6 +++--- drivers/md/md.h | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-)
drivers/md/md.c +3 -3
@@ -6063,7 +6063,7 @@ int md_run(struct mddev *mddev)* the only valid external interface is through the md * device. */ - mddev->has_superblocks = false; +clear_bit (MD_HAS_SUPERBLOCK , &mddev->flags);rdev_for_each (rdev, mddev) {if (test_bit (Faulty, &rdev->flags))continue ;
@@ -6076,7 +6076,7 @@ int md_run(struct mddev *mddev) }if (rdev->sb_page) - mddev->has_superblocks = true; +set_bit (MD_HAS_SUPERBLOCK , &mddev->flags);/* perform some consistency tests on the device. * We don't want the data to overlap the metadata,
@@ -8722,7 +8722,7 @@ void md_write_start(struct mddev *mddev, struct bio *bi)rcu_read_unlock ();if (did_change)sysfs_notify_dirent_safe (mddev->sysfs_state); -if (!mddev->has_superblocks) +if (!test_bit (MD_HAS_SUPERBLOCK , &mddev->flags))return ;wait_event (mddev->sb_wait, !test_bit (MD_SB_CHANGE_PENDING , &mddev->sb_flags));
drivers/md/md.h +2 -1
@@ -312,6 +312,7 @@ struct md_cluster_info;* array is ready yet. * @MD_BROKEN: This is used to stop writes and mark array as failed. * @MD_DELETED: This device is being deleted +* @MD_HAS_SUPERBLOCK: There is persistence sb in member disks. * * change UNSUPPORTED_MDDEV_FLAGS for each array type if new flag is added */
@@ -327,6 +328,7 @@ enum mddev_flags {MD_NOT_READY ,MD_BROKEN ,MD_DELETED , + MD_HAS_SUPERBLOCK, }; enum mddev_sb_flags {
@@ -587,7 +589,6 @@ struct mddev {/* The sequence number for sync thread */ atomic_t sync_seq; - bool has_superblocks:1; bool fail_last_dev:1; bool serialize_policy:1; };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 791/1376 md: merge mddev faillast_dev into mddev_flags
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yu Kuai <[email protected]>
[ Upstream commit 4f6d2e648cbe963b328cb8815290676da3866434 ]
There is not need to use a separate field in struct mddev, there are no functional changes.
Stable-dep-of: 140234b2380f ("md/raid1: create serial pool adding rdev to array with serialize_policy=1")
--- drivers/md/md.c | 10 ++++++---- drivers/md/md.h | 3 ++- drivers/md/raid0.c | 3 ++- drivers/md/raid1.c | 4 ++-- drivers/md/raid10.c | 4 ++-- drivers/md/raid5.c | 5 ++++- 6 files changed, 18 insertions(+), 11 deletions(-)
drivers/md/md.c +6 -4
@@ -5582,11 +5582,11 @@ __ATTR(consistency_policy, S_IRUGO | S_IWUSR, consistency_policy_show,static ssize_t fail_last_dev_show (struct mddev *mddev,char *page) { -return sprintf (page,"%d\n" , mddev->fail_last_dev); +return sprintf (page,"%d\n" ,test_bit (MD_FAILLAST_DEV , &mddev->flags)); }/* -* Setting fail_last_dev to true to allow last device to be forcibly removed +* Setting MD_FAILLAST_DEV to allow last device to be forcibly removed * from RAID1/RAID10. */ static ssize_t
@@ -5599,8 +5599,10 @@ fail_last_dev_store(struct mddev *mddev, const char *buf, size_t len)if (ret)return ret; -if (value != mddev->fail_last_dev) - mddev->fail_last_dev = value; +if (value) +set_bit (MD_FAILLAST_DEV , &mddev->flags); +else +clear_bit (MD_FAILLAST_DEV , &mddev->flags);return len; }
drivers/md/md.h +2 -1
@@ -313,6 +313,7 @@ struct md_cluster_info;* @MD_BROKEN: This is used to stop writes and mark array as failed. * @MD_DELETED: This device is being deleted * @MD_HAS_SUPERBLOCK: There is persistence sb in member disks. +* @MD_FAILLAST_DEV: Allow last rdev to be removed. * * change UNSUPPORTED_MDDEV_FLAGS for each array type if new flag is added */
@@ -329,6 +330,7 @@ enum mddev_flags {MD_BROKEN ,MD_DELETED ,MD_HAS_SUPERBLOCK , + MD_FAILLAST_DEV, }; enum mddev_sb_flags {
@@ -589,7 +591,6 @@ struct mddev {/* The sequence number for sync thread */ atomic_t sync_seq; - bool fail_last_dev:1; bool serialize_policy:1; };
drivers/md/raid0.c +2 -1
@@ -27,7 +27,8 @@ module_param(default_layout, int, 0644); (1L <<MD_JOURNAL_CLEAN ) | \ (1L <<MD_FAILFAST_SUPPORTED ) |\ (1L <<MD_HAS_PPL ) | \ - (1L << MD_HAS_MULTIPLE_PPLS)) + (1L <<MD_HAS_MULTIPLE_PPLS ) | \ + (1L << MD_FAILLAST_DEV))/* * inform the user of the raid configuration
drivers/md/raid1.c +2 -2
@@ -1741,7 +1741,7 @@ static void raid1_status(struct seq_file *seq, struct mddev *mddev)* - &mddev->degraded is bumped. * * @rdev is marked as &Faulty excluding case when array is failed and -* &mddev->fail_last_dev is off. +* MD_FAILLAST_DEV is not set. */ static void raid1_error (struct mddev *mddev,struct md_rdev *rdev) {
@@ -1754,7 +1754,7 @@ static void raid1_error(struct mddev *mddev, struct md_rdev *rdev) (conf->raid_disks - mddev->degraded) == 1) {set_bit (MD_BROKEN , &mddev->flags); -if (!mddev->fail_last_dev) { +if (!test_bit (MD_FAILLAST_DEV , &mddev->flags)) { conf->recovery_disabled = mddev->recovery_disabled;spin_unlock_irqrestore (&conf->device_lock, flags);return ;
drivers/md/raid10.c +2 -2
@@ -1994,7 +1994,7 @@ static int enough(struct r10conf *conf, int ignore)* - &mddev->degraded is bumped. * * @rdev is marked as &Faulty excluding case when array is failed and -* &mddev->fail_last_dev is off. +* MD_FAILLAST_DEV is not set. */ static void raid10_error (struct mddev *mddev,struct md_rdev *rdev) {
@@ -2006,7 +2006,7 @@ static void raid10_error(struct mddev *mddev, struct md_rdev *rdev)if (test_bit (In_sync, &rdev->flags) && !enough (conf, rdev->raid_disk)) {set_bit (MD_BROKEN , &mddev->flags); -if (!mddev->fail_last_dev) { +if (!test_bit (MD_FAILLAST_DEV , &mddev->flags)) {spin_unlock_irqrestore (&conf->device_lock, flags);return ; }
drivers/md/raid5.c +4 -1
@@ -56,7 +56,10 @@#include "md-bitmap.h" #include "raid5-log.h" -#define UNSUPPORTED_MDDEV_FLAGS (1L << MD_FAILFAST_SUPPORTED) +#define UNSUPPORTED_MDDEV_FLAGS \ + ((1L << MD_FAILFAST_SUPPORTED) | \ + (1L << MD_FAILLAST_DEV)) +#define cpu_to_group (cpu) cpu_to_node(cpu)#define ANY_GROUP NUMA_NO_NODE
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 792/1376 md: merge mddev serialize_policy into mddev_flags
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yu Kuai <[email protected]>
[ Upstream commit 10787568cc1f3f80afc510b2728751989dfa0ae6 ]
There is not need to use a separate field in struct mddev, there are no functional changes.
Stable-dep-of: 140234b2380f ("md/raid1: create serial pool adding rdev to array with serialize_policy=1")
--- drivers/md/md-bitmap.c | 4 ++-- drivers/md/md.c | 20 ++++++++++++-------- drivers/md/md.h | 4 ++-- drivers/md/raid0.c | 3 ++- drivers/md/raid1.c | 4 ++-- drivers/md/raid5.c | 3 ++- 6 files changed, 22 insertions(+), 16 deletions(-)
drivers/md/md-bitmap.c +2 -2
@@ -2097,7 +2097,7 @@ static void bitmap_destroy(struct mddev *mddev)return ;bitmap_wait_behind_writes (mddev); -if (!mddev->serialize_policy) +if (!test_bit (MD_SERIALIZE_POLICY , &mddev->flags))mddev_destroy_serial_pool (mddev,NULL );mutex_lock (&mddev->bitmap_info.mutex);
@@ -2826,7 +2826,7 @@ backlog_store(struct mddev *mddev, const char *buf, size_t len) mddev->bitmap_info.max_write_behind = backlog;if (!backlog && mddev->serial_info_pool) {/* serial_info_pool is not needed if backlog is zero */ -if (!mddev->serialize_policy) +if (!test_bit (MD_SERIALIZE_POLICY , &mddev->flags))mddev_destroy_serial_pool (mddev,NULL ); }else if (backlog && !mddev->serial_info_pool) {/* serial_info_pool is needed since backlog is not zero */
drivers/md/md.c +12 -8
@@ -270,7 +270,8 @@ void mddev_destroy_serial_pool(struct mddev *mddev, struct md_rdev *rdev)rdev_for_each (temp, mddev) {if (!rdev) { -if (!mddev->serialize_policy || +if (!test_bit (MD_SERIALIZE_POLICY , + &mddev->flags) || !rdev_need_serial (temp))rdev_uninit_serial (temp);else
@@ -5615,11 +5616,12 @@ static ssize_t serialize_policy_show(struct mddev *mddev, char *page)if (mddev->pers ==NULL || (mddev->pers->level !=1 ))return sprintf (page,"n/a\n" );else -return sprintf (page,"%d\n" , mddev->serialize_policy); +return sprintf (page,"%d\n" , +test_bit (MD_SERIALIZE_POLICY , &mddev->flags)); }/* -* Setting serialize_policy to true to enforce write IO is not reordered +* Setting MD_SERIALIZE_POLICY enforce write IO is not reordered * for raid1. */ static ssize_t
@@ -5632,7 +5634,7 @@ serialize_policy_store(struct mddev *mddev, const char *buf, size_t len)if (err)return err; -if (value == mddev->serialize_policy) +if (value ==test_bit (MD_SERIALIZE_POLICY , &mddev->flags))return len; err =mddev_suspend_and_lock (mddev);
@@ -5644,11 +5646,13 @@ serialize_policy_store(struct mddev *mddev, const char *buf, size_t len) goto unlock; } -if (value) +if (value) {mddev_create_serial_pool (mddev,NULL ); -else +set_bit (MD_SERIALIZE_POLICY , &mddev->flags); + }else {mddev_destroy_serial_pool (mddev,NULL ); - mddev->serialize_policy = value; +clear_bit (MD_SERIALIZE_POLICY , &mddev->flags); + } unlock:mddev_unlock_and_resume (mddev);return err ?: len;
@@ -6453,7 +6457,7 @@ static void __md_stop_writes(struct mddev *mddev)md_update_sb (mddev,1 ); }/* disable policy to guarantee rdevs free resources for serialization */ - mddev->serialize_policy =0 ; +clear_bit (MD_SERIALIZE_POLICY , &mddev->flags);mddev_destroy_serial_pool (mddev,NULL ); }
drivers/md/md.h +2 -2
@@ -314,6 +314,7 @@ struct md_cluster_info;* @MD_DELETED: This device is being deleted * @MD_HAS_SUPERBLOCK: There is persistence sb in member disks. * @MD_FAILLAST_DEV: Allow last rdev to be removed. +* @MD_SERIALIZE_POLICY: Enforce write IO is not reordered, just used by raid1. * * change UNSUPPORTED_MDDEV_FLAGS for each array type if new flag is added */
@@ -331,6 +332,7 @@ enum mddev_flags {MD_DELETED ,MD_HAS_SUPERBLOCK ,MD_FAILLAST_DEV , + MD_SERIALIZE_POLICY, }; enum mddev_sb_flags {
@@ -590,8 +592,6 @@ struct mddev {/* The sequence number for sync thread */ atomic_t sync_seq; - - bool serialize_policy:1; };enum recovery_flags {
drivers/md/raid0.c +2 -1
@@ -28,7 +28,8 @@ module_param(default_layout, int, 0644); (1L <<MD_FAILFAST_SUPPORTED ) |\ (1L <<MD_HAS_PPL ) | \ (1L <<MD_HAS_MULTIPLE_PPLS ) | \ - (1L << MD_FAILLAST_DEV)) + (1L <<MD_FAILLAST_DEV ) | \ + (1L << MD_SERIALIZE_POLICY))/* * inform the user of the raid configuration
drivers/md/raid1.c +2 -2
@@ -542,7 +542,7 @@ static void raid1_end_write_request(struct bio *bio)call_bio_endio (r1_bio); } } - }else if (rdev->mddev->serialize_policy) + }else if (test_bit (MD_SERIALIZE_POLICY , &rdev->mddev->flags))remove_serial (rdev, lo, hi);if (r1_bio->bios[mirror] ==NULL )rdev_dec_pending (rdev, conf->mddev);
@@ -1637,7 +1637,7 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio, mbio =bio_alloc_clone (rdev->bdev, bio,GFP_NOIO , &mddev->bio_set); -if (mddev->serialize_policy) +if (test_bit (MD_SERIALIZE_POLICY , &mddev->flags))wait_for_serialization (rdev, r1_bio); }
drivers/md/raid5.c +2 -1
@@ -58,7 +58,8 @@#define UNSUPPORTED_MDDEV_FLAGS \ ((1L << MD_FAILFAST_SUPPORTED) | \ - (1L << MD_FAILLAST_DEV)) + (1L << MD_FAILLAST_DEV) | \ + (1L << MD_SERIALIZE_POLICY))#define cpu_to_group (cpu) cpu_to_node(cpu)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 793/1376 md/raid1: create serial pool adding rdev to array with serialize_policy=1
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Martin Wilck <[email protected]>
[ Upstream commit 140234b2380ffb8ffb0cfc46fee0e822f43adef7 ]
The following bug has been observed with kernel 7.1.3 after adding a new rdev to an existing RAID1 array with serialize_policy enabled:
Oops: 0002 [#1] CPU: 0 UID: 0 PID: 19639 Comm: ext4lazyinit Not tainted 7.1.3-1-default RIP: _raw_spin_lock_irqsave+0x27/0x50 CR2: 0000000000004960 Call Trace: wait_for_serialization+0xb9/0x260 [raid1] raid1_make_request+0x762/0xaff [raid1] md_handle_request+0x1c9/0x2e0 [md_mod]
The raid1.c code calls wait_for_serialization() if the MD_SERIALIZE_POLICY is set, and wait_for_serialization assumes that rdev->serial is initialized. Normally this will be the case for arrays that have the serialize_policy sysfs attribute set to 1.
But when a new rdev is added to an existing array in bind_rdev_to_array(), the condition at mddev_create_serial_pool() causes creation of rdev->serial to be skipped. Fix it.
--- drivers/md/md.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/md/md.c +2 -1
@@ -228,7 +228,8 @@ void mddev_create_serial_pool(struct mddev *mddev, struct md_rdev *rdev)int ret =0 ;unsigned int noio_flags; -if (rdev && !rdev_need_serial (rdev) && +if (!test_bit (MD_SERIALIZE_POLICY , &mddev->flags) && + rdev && !rdev_need_serial (rdev) && !test_bit (CollisionCheck, &rdev->flags))return ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 794/1376 locking/lockdep: Fix NULL pointer dereference in __lock_set_class()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Naveen Kumar Chaudhary <[email protected]>
[ Upstream commit 7577e00b9ab506202b9f1a33de3cc8cc6413a4db ]
register_lock_class() can return NULL when the lock class pool is exhausted, graph_lock() fails, or key validation fails. However, __lock_set_class() uses the return value directly in pointer arithmetic without a NULL check:
class = register_lock_class(lock, subclass, 0); hlock->class_idx = class - lock_classes;
If class is NULL, this computes a wild offset that corrupts hlock->class_idx. The subsequent reacquire_held_locks() call will invoke hlock_class() with this corrupted index, leading to a NULL or out-of-bounds pointer dereference.
Add the missing NULL check, consistent with how __lock_acquire() already handles this case at the same call site.
--- kernel/locking/lockdep.c | 2 ++ 1 file changed, 2 insertions(+)
kernel/locking/lockdep.c +2 -0
@@ -5402,6 +5402,8 @@ __lock_set_class(struct lockdep_map *lock, const char *name, lock->wait_type_outer, lock->lock_type); class =register_lock_class (lock, subclass,0 ); +if (!class) +return 0 ; hlock->class_idx = class - lock_classes; curr->lockdep_depth = i;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 795/1376 powerpc/crash: Fix possible memory leak in update_crash_elfcorehdr()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jinjie Ruan <[email protected]>
[ Upstream commit 4cc4b586007fbbf8edba4f1d0849e9a06b0cf6c3 ]
In get_crash_memory_ranges(), if crash_exclude_mem_range() failed after realloc_mem_ranges() has successfully allocated the cmem memory, it just returns an error but leaves cmem pointing to the allocated memory, nor is it freed in the caller update_crash_elfcorehdr(), which cause a memory leak, goto out to free the cmem.
--- arch/powerpc/kexec/crash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/powerpc/kexec/crash.c +1 -1
@@ -502,7 +502,7 @@ static void update_crash_elfcorehdr(struct kimage *image, struct memory_notify * ret =get_crash_memory_ranges (&cmem);if (ret) {pr_err ("Failed to get crash mem range\n" ); -return ; + goto out; }/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 796/1376 misc: vmc_vmci: Fix potential memory leak in vmci_event_subscribe()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abdun Nihaal <[email protected]>
[ Upstream commit 210854a96ef18b09b45a2a59ff14ca06dfe5ad4d ]
The memory allocated for struct vmci_subscription (sub) is not freed in the error path when have_new_id is false. Fix that by adding a kfree() call, and moving the read of sub->id to a point before freeing.
--- drivers/misc/vmw_vmci/vmci_event.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/misc/vmw_vmci/vmci_event.c +2 -2
@@ -179,16 +179,16 @@ int vmci_event_subscribe(u32 event, } } + *new_subscription_id = sub->id;if (have_new_id) {list_add_rcu (&sub->node, &subscriber_array[event]); retval =VMCI_SUCCESS ; }else { +kfree (sub); retval =VMCI_ERROR_NO_RESOURCES ; }mutex_unlock (&subscriber_mutex); - - *new_subscription_id = sub->id;return retval; }EXPORT_SYMBOL_GPL (vmci_event_subscribe);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 797/1376 misc: sgi-gru: remove interrupt-context page-table walks
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Muhammad Usama Anjum <[email protected]>
[ Upstream commit 928a8e9f523df845fc496bcb9811013b67aabec5 ]
The GRU TLB miss handler walks a process's page tables without holding page-table locks or a reference to the mapped page. It also uses a kernel page-table accessor on user page tables and supports only PMD-level large mappings on x86-64.
Remove the direct walker. Send interrupt faults directly to user polling mode so the existing call-OS fallback retries them in process context.
Remove the mmap-lock failure statistic that can no longer be incremented.
--- drivers/misc/sgi-gru/grufault.c | 101 ++++--------------------------- drivers/misc/sgi-gru/gruprocfs.c | 1 - drivers/misc/sgi-gru/grutables.h | 1 - 3 files changed, 12 insertions(+), 91 deletions(-)
drivers/misc/sgi-gru/grufault.c +12 -89
@@ -166,13 +166,8 @@ static void get_clear_fault_map(struct gru_state *gru, }/* -* Atomic (interrupt context) & non-atomic (user context) functions to -* convert a vaddr into a physical address. The size of the page -* is returned in pageshift. -* returns: -* 0 - successful -* < 0 - error code -* 1 - (atomic only) try again in non-atomic context +* Convert a user virtual address to a physical address in process context. +* The size of the page is returned in pageshift. */ static int non_atomic_pte_lookup(struct vm_area_struct *vma, unsigned long vaddr, int write,
@@ -192,87 +187,25 @@ static int non_atomic_pte_lookup(struct vm_area_struct *vma,return 0 ; } -/* -* atomic_pte_lookup -* -* Convert a user virtual address to a physical address -* Only supports Intel large pages (2MB only) on x86_64. -* ZZZ - hugepage support is incomplete -* -* NOTE: mmap_lock is already held on entry to this function. This -* guarantees existence of the page tables. -*/ -static int atomic_pte_lookup (struct vm_area_struct *vma,unsigned long vaddr, -int write,unsigned long *paddr,int *pageshift) -{ -pgd_t *pgdp; -p4d_t *p4dp; -pud_t *pudp; -pmd_t *pmdp; -pte_t pte; - - pgdp =pgd_offset (vma->vm_mm, vaddr); -if (unlikely (pgd_none (*pgdp))) - goto err; - - p4dp =p4d_offset (pgdp, vaddr); -if (unlikely (p4d_none (*p4dp))) - goto err; - - pudp =pud_offset (p4dp, vaddr); -if (unlikely (pud_none (*pudp))) - goto err; - - pmdp =pmd_offset (pudp, vaddr); -if (unlikely (pmd_none (*pmdp))) - goto err; -#ifdef CONFIG_X86_64 -if (unlikely (pmd_leaf (*pmdp))) - pte =ptep_get ((pte_t *)pmdp); - else -#endif - pte = *pte_offset_kernel (pmdp, vaddr); - -if (unlikely (!pte_present (pte) || - (write && (!pte_write (pte) || !pte_dirty (pte))))) -return 1 ; - - *paddr =pte_pfn (pte) <<PAGE_SHIFT ; -#ifdef CONFIG_HUGETLB_PAGE - *pageshift =is_vm_hugetlb_page (vma) ?HPAGE_SHIFT :PAGE_SHIFT ; -#else - *pageshift =PAGE_SHIFT ; -#endif -return 0 ; - -err: -return 1 ; -} -static int gru_vtop (struct gru_thread_state *gts,unsigned long vaddr,int write,int atomic,unsigned long *gpa,int *pageshift) {struct mm_struct *mm = gts->ts_mm;struct vm_area_struct *vma;unsigned long paddr; -int ret, ps; +int ps; vma =find_vma (mm, vaddr);if (!vma) goto inval; -/* -* Atomic lookup is faster & usually works even if called in non-atomic -* context. -*/ -rmb ();/* Must/check ms_range_active before loading PTEs */ - ret =atomic_pte_lookup (vma, vaddr, write, &paddr, &ps); -if (ret) { -if (atomic) - goto upm; -if (non_atomic_pte_lookup (vma, vaddr, write, &paddr, &ps)) - goto inval; - } +if (atomic) + goto upm; + +/* Order the caller's ms_range_active check before loading PTEs. */ +rmb (); +if (non_atomic_pte_lookup (vma, vaddr, write, &paddr, &ps)) + goto inval;if (is_gru_paddr (paddr)) goto inval; paddr = paddr & ~((1UL << ps) -1 );
@@ -569,19 +502,9 @@ static irqreturn_t gru_intr(int chiplet, int blade)continue ; } -/* -* This is running in interrupt context. Trylock the mmap_lock. -* If it fails, retry the fault in user context. -*/ +/* Address translation may sleep, so retry the fault in user context. */ gts->ustats.fmm_tlbmiss++; -if (!gts->ts_force_cch_reload && -mmap_read_trylock (gts->ts_mm)) { -gru_try_dropin (gru, gts, tfh,NULL ); -mmap_read_unlock (gts->ts_mm); - }else { -tfh_user_polling_mode (tfh); -STAT (intr_mm_lock_failed); - } +tfh_user_polling_mode (tfh); }return IRQ_HANDLED ; }
drivers/misc/sgi-gru/gruprocfs.c +0 -1
@@ -54,7 +54,6 @@ static int statistics_show(struct seq_file *s, void *p)printstat (s, intr_cbr);printstat (s, intr_tfh);printstat (s, intr_spurious); -printstat (s, intr_mm_lock_failed);printstat (s, call_os);printstat (s, call_os_wait_queue);printstat (s, user_flush_tlb);
drivers/misc/sgi-gru/grutables.h +0 -1
@@ -182,7 +182,6 @@ struct gru_stats_s {atomic_long_t intr_cbr;atomic_long_t intr_tfh;atomic_long_t intr_spurious; -atomic_long_t intr_mm_lock_failed;atomic_long_t call_os;atomic_long_t call_os_wait_queue;atomic_long_t user_flush_tlb;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 798/1376 fanotify: report full event length for FIONREAD
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yichong Chen <[email protected]>
[ Upstream commit 68615158c12de36220446dfea5cfdf9ba6c19690 ]
fanotify_ioctl(FIONREAD) reports the number of bytes available to read from the event queue. It currently accounts only FAN_EVENT_METADATA_LEN for each queued event.
That underestimates events that carry additional information records, such as FAN_REPORT_DFID_NAME events. A userspace program that uses FIONREAD to size its read buffer can receive a length that is smaller than the next event. Reading with that buffer then fails with -EINVAL, while a larger buffer succeeds and reports a larger metadata.event_len.
Use fanotify_event_len() when summing queued events so FIONREAD includes all info records.
--- fs/notify/fanotify/fanotify_user.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
fs/notify/fanotify/fanotify_user.c +4 -1
@@ -970,11 +970,13 @@ static long fanotify_ioctl(struct file *file, unsigned int cmd, unsigned long ar {struct fsnotify_group *group;struct fsnotify_event *fsn_event; +unsigned int info_mode;void __user *p;int ret = -ENOTTY ;size_t send_len =0 ; group = file->private_data; + info_mode =FAN_GROUP_FLAG (group,FANOTIFY_INFO_MODES ); p = (void __user *) arg;
@@ -982,7 +984,8 @@ static long fanotify_ioctl(struct file *file, unsigned int cmd, unsigned long arcase FIONREAD :spin_lock (&group->notification_lock);list_for_each_entry (fsn_event, &group->notification_list, list) - send_len +=FAN_EVENT_METADATA_LEN ; + send_len +=fanotify_event_len (info_mode, +FANOTIFY_E (fsn_event));spin_unlock (&group->notification_lock); ret =put_user (send_len, (int __user *) p);break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 799/1376 wifi: mt76: mt76x02: do not WARN on invalid rx descriptor length
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Devin Wittmayer <[email protected]>
[ Upstream commit 81497634d9f872fd3e8b03aada55574afff6f174 ]
The MPDU length in the rx descriptor comes from the hardware. In monitor mode with the fcsfail filter enabled, the hardware passes up corrupted frames, and a corrupted frame can report a length larger than the received buffer. The bounds check correctly discards such frames, but its WARN_ON_ONCE wrapper means any over-the-air garbage frame taints the kernel, and panics it on the first such frame when panic_on_warn is set.
Drop the WARN and discard the frame silently, matching what commit c2d4c8723dbf ("mt76x2: remove some harmless WARN_ONs in tx status and rx path") did for the neighboring rx and tx status paths.
Observed immediately on rx with an MT7612U in fcsfail monitor mode on a busy channel.
--- drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +1 -1
@@ -850,7 +850,7 @@ int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, } } -if (WARN_ON_ONCE (len > skb->len)) +if (len > skb->len)return -EINVAL ;if (pskb_trim (skb, len))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 800/1376 wifi: mt76: mt7921: validate CLC firmware records
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Laxman Acharya Padhya <[email protected]>
[ Upstream commit 9417c5818a0146980c2608fda94c908e604eb033 ]
The CLC region is supplied by firmware, but the loader trusts the region count and each record length. A malformed image can make the region table pointer precede the firmware buffer, make the record loop fail to advance, or index phy->clc past its end. Validate the table and record bounds before dereferencing or copying.
--- .../net/wireless/mediatek/mt76/mt7921/mcu.c | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +24 -4
@@ -412,7 +412,8 @@ static int mt7921_load_clc(struct mt792x_dev *dev, const char *fw_name)struct mt76_dev *mdev = &dev->mt76;struct mt792x_phy *phy = &dev->phy;const struct firmware *fw; -int ret, i, len, offset =0 ; +size_t clc_len, fw_data_len, len, offset =0 ; +int ret, i;u8 *clc_base =NULL , hw_encap =0 ; dev->phy.clc_chan_conf =0xff ;
@@ -438,13 +439,21 @@ static int mt7921_load_clc(struct mt792x_dev *dev, const char *fw_name) } hdr = (const void *)(fw->data + fw->size -sizeof (*hdr)); +if (hdr->n_region > (fw->size -sizeof (*hdr)) /sizeof (*region)) { +dev_err (mdev->dev,"Invalid firmware region table\n" ); + ret = -EINVAL ; + goto out; + } + fw_data_len = fw->size -sizeof (*hdr) - + hdr->n_region *sizeof (*region); +for (i =0 ; i < hdr->n_region; i++) { region = (const void *)((const u8 *)hdr - (hdr->n_region - i) *sizeof (*region)); len =le32_to_cpu (region->len);/* check if we have valid buffer size */ -if (offset + len > fw->size) { +if (len > fw_data_len - offset) {dev_err (mdev->dev,"Invalid firmware region\n" ); ret = -EINVAL ; goto out;
@@ -461,8 +470,19 @@ static int mt7921_load_clc(struct mt792x_dev *dev, const char *fw_name)if (!clc_base) goto out; -for (offset =0 ; offset < len; offset +=le32_to_cpu (clc->len)) { +for (offset =0 ; offset < len; offset += clc_len) { +if (len - offset <sizeof (*clc)) { + ret = -EINVAL ; + goto out; + } + clc = (const struct mt7921_clc *)(clc_base + offset); + clc_len =le32_to_cpu (clc->len); +if (clc_len <sizeof (*clc) || clc_len > len - offset || + clc->idx >=ARRAY_SIZE (phy->clc)) { + ret = -EINVAL ; + goto out; + }/* do not init buf again if chip reset triggered */ if (phy->clc[clc->idx])
@@ -474,7 +494,7 @@ static int mt7921_load_clc(struct mt792x_dev *dev, const char *fw_name)continue ; phy->clc[clc->idx] =devm_kmemdup (mdev->dev, clc, -le32_to_cpu (clc->len), + clc_len,GFP_KERNEL );if (!phy->clc[clc->idx]) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 801/1376 wifi: mt76: mt7915: fix net_fill_forward_path for non-DBDC mt7986
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhi-Jun You <[email protected]>
[ Upstream commit bade0d238b60c29dafcc7da17501fa489495d6ae ]
Current implementation assumes that the hardware supports DBDC or single band and binds to band0.
This causes net_fill_forward_path to select the wrong queue for non-DBDC mt7986 because it binds to band1 and getting the following in dmesg:
ieee80211 phy2: WA: --> drop by reaseon:1, msdu id = 0xc002 but failed!mtk_wed1: error status=00000002
ieee80211 phy2: WA: txblk10324e00
len = 128
DW0 : 10 00 00 00
DW1 : 00 00 00 00
DW2 : 00 00 00 00
DW3 : 72 0f 94 68
DW4 : 00 00 00 00
DW5 : ff 03 00 00
DW6 : 00 00 3c 40
DW7 : 00 17 dd 14
DW8 : 79 6f 00 00
DW9 : 02 c0 00 00
DW10 : 58 c5 34 10
DW11 : 00 00 00 00
DW12 : 00 06 3e 00
DW13 : 00 00 00 80
DW14 : 10 8c 00 00
DW15 : 00 00 00 00
DW16 : 00 00 00 00
DW17 : 00 00 00 00
DW18 : 00 00 00 00
DW19 : 00 00 00 00
DW20 : 00 00 00 00
DW21 : 00 00 00 00
DW22 : 00 00 00 00
DW23 : 00 00 00 00
DW24 : 00 00 00 00
DW25 : 00 00 00 00
DW26 : 00 00 00 00
DW27 : 00 00 00 00
DW28 : 00 00 00 00
DW29 : 00 00 00 00
DW30 : 00 00 00 00
DW31 : 00 00 00 00
Fix it by using phy->mt76->band_idx for queue which works for both non-DBDC and DBDC devices.
--- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mt7915/main.c +1 -1
@@ -1676,7 +1676,7 @@ mt7915_net_fill_forward_path(struct ieee80211_hw *hw, path->mtk_wdma.wdma_idx = wed->wdma_idx; path->mtk_wdma.bss = mvif->mt76.idx; path->mtk_wdma.wcid =is_mt7915 (&dev->mt76) ? msta->wcid.idx :0x3ff ; - path->mtk_wdma.queue = phy != &dev->phy; + path->mtk_wdma.queue = phy->mt76->band_idx; ctx->dev =NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 802/1376 wifi: mt76: add init_wiphy callback
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Wang <[email protected]>
[ Upstream commit 4ee3d2a5f2cd5b6d0ba0d997913c1b763ef4d5c5 ]
Add an optional callback for drivers to finalize wiphy state after mt76 has initialized the supported bands and before registration.
Stable-dep-of: 217f9e7bb025 ("wifi: mt76: mt792x: fix use-after-free in mt76_rx_poll_complete")
--- drivers/net/wireless/mediatek/mt76/mac80211.c | 7 +++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 3 +++ 2 files changed, 10 insertions(+)
drivers/net/wireless/mediatek/mt76/mac80211.c +7 -0
@@ -644,6 +644,7 @@ mt76_alloc_device(struct device *pdev, unsigned int size, dev = hw->priv; dev->hw = hw; dev->dev = pdev; + dev->init_wiphy =NULL ; dev->drv = drv_ops; dev->dma_dev = pdev;
@@ -740,6 +741,12 @@ int mt76_register_device(struct mt76_dev *dev, bool vht,mt76_check_sband (&dev->phy, &phy->sband_5g,NL80211_BAND_5GHZ );mt76_check_sband (&dev->phy, &phy->sband_6g,NL80211_BAND_6GHZ ); +if (dev->init_wiphy) { + ret = dev->init_wiphy (dev); +if (ret) +return ret; + } +if (IS_ENABLED (CONFIG_MT76_LEDS )) { ret =mt76_led_init (phy);if (ret)
drivers/net/wireless/mediatek/mt76/mt76.h +3 -0
@@ -845,6 +845,9 @@ struct mt76_dev {const struct mt76_bus_ops *bus;const struct mt76_driver_ops *drv;const struct mt76_mcu_ops *mcu_ops; + +/* Optional callback to finalize wiphy state before registration. */ +int (*init_wiphy)(struct mt76_dev *dev);struct device *dev;struct device *dma_dev;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 803/1376 wifi: mt76: mt792x: fix use-after-free in mt76_rx_poll_complete
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eason Lai <[email protected]>
[ Upstream commit 217f9e7bb02558759be9d9ecfe532e9708741c50 ]
A use-after-free issue occurs in mt76_rx_poll_complete due to a race condition. The STA has already been removed, but the rx_status still had a pointer to the wcid in the STA.
Set the links' wcid pointers to be NULL for a MLD in mt7925_sta_pre_rcu_remove()
BUG: KASAN: invalid-access in mt76_rx_poll_complete+0x280/0x470 Call trace: dump_backtrace+0xec/0x128 show_stack+0x18/0x28 dump_stack_lvl+0x40/0xc8 print_report+0x1b8/0x710 kasan_report+0xe0/0x144 do_bad_area+0x120/0x260 do_tag_check_fault+0x20/0x34 do_mem_abort+0x54/0xa8 el1_abort+0x3c/0x5c el1h_64_sync_handler+0x40/0xcc el1h_64_sync+0x7c/0x80 mt76_rx_poll_complete+0x280/0x470 mt76_dma_rx_poll+0x114/0x51c mt792x_poll_rx+0x60/0xf8 napi_threaded_poll_loop+0xe0/0x450 napi_threaded_poll+0x80/0x9c kthread+0x11c/0x158 ret_from_fork+0x10/0x20
--- .../net/wireless/mediatek/mt76/mt7925/main.c | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mt7925/main.c +35 -1
@@ -2165,6 +2165,40 @@ static void mt7925_unassign_vif_chanctx(struct ieee80211_hw *hw,mutex_unlock (&dev->mt76.mutex); } +static void mt7925_sta_pre_rcu_remove (struct ieee80211_hw *hw, +struct ieee80211_vif *vif, +struct ieee80211_sta *sta) +{ +struct mt76_phy *phy = hw->priv; +struct mt76_dev *dev = phy->dev; +struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; + +mutex_lock (&dev->mutex); +spin_lock_bh (&dev->status_lock); + +if (ieee80211_vif_is_mld (vif)) { +struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; +struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; +unsigned long valid = mvif->valid_links; +struct mt792x_link_sta *mlink; +unsigned int link_id; + +for_each_set_bit (link_id, &valid,IEEE80211_MLD_MAX_NUM_LINKS ) { + mlink =mt792x_sta_to_link (msta, link_id); +if (!mlink || !mlink->wcid.sta) +continue ; +if (mlink->wcid.idx <ARRAY_SIZE (dev->wcid)) +rcu_assign_pointer (dev->wcid[mlink->wcid.idx], +NULL ); + } + }else { +rcu_assign_pointer (dev->wcid[wcid->idx],NULL ); + } + +spin_unlock_bh (&dev->status_lock); +mutex_unlock (&dev->mutex); +} +const struct ieee80211_ops mt7925_ops = { .tx = mt792x_tx, .start = mt7925_start,
@@ -2177,7 +2211,7 @@ const struct ieee80211_ops mt7925_ops = { .start_ap = mt7925_start_ap, .stop_ap = mt7925_stop_ap, .sta_state = mt76_sta_state, - .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, + .sta_pre_rcu_remove = mt7925_sta_pre_rcu_remove, .set_key = mt7925_set_key, .sta_set_decap_offload = mt7925_sta_set_decap_offload,#if IS_ENABLED (CONFIG_IPV6 )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 804/1376 wifi: mt76: mt7925: fix msg len mismatch between driver and firmware
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jared.Huang <[email protected]>
[ Upstream commit 9ddb7487aa7cccb6e1880b4151ab5895109eb8d6 ]
The mt7925_tx_power_limit_tlv struct begins with a 4-byte rsv[] field that acts as a UNI command header prefix. The firmware dispatcher did not use the 4-byte rsv[] and will only check the payloads after the 4-byte rsv[] As a result, the total message length minus the 4-byte prefix. Fix this by setting len to msg_len - 4.
--- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +1 -1
@@ -3602,7 +3602,7 @@ mt7925_mcu_rate_txpower_band(struct mt76_phy *phy,memcpy (tx_power_tlv->alpha2, dev->alpha2,sizeof (dev->alpha2)); tx_power_tlv->n_chan = num_ch; tx_power_tlv->tag =cpu_to_le16 (0x1 ); - tx_power_tlv->len =cpu_to_le16 (msg_len); + tx_power_tlv->len =cpu_to_le16 (msg_len -4 );switch (band) {case NL80211_BAND_2GHZ :
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 805/1376 wifi: mt76: mt792x: Fix memory leak in SDIO TX path
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eason Lai <[email protected]>
[ Upstream commit 808f2767d4217a5b96f674288573b9b89d432eed ]
When tx_prepare_skb() returns an error in the SDIO TX path, the skb is not freed, leading to a memory leak. This can occur when zero-length frames (such as WNM NULL frames) are dropped to prevent potential hardware TX hangs.
Fix this by properly releasing the skb with ieee80211_tx_status_ext() when tx_prepare_skb() fails.
--- drivers/net/wireless/mediatek/mt76/sdio.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/sdio.c +10 -1
@@ -519,6 +519,10 @@ mt76s_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q, enum mt76_txq_id qid, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta) { + struct ieee80211_tx_status status = { + .sta = sta, + }; +struct mt76_tx_info tx_info = { .skb = skb, };
@@ -531,8 +535,13 @@ mt76s_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q, skb->prev = skb->next =NULL ; err = dev->drv->tx_prepare_skb (dev,NULL , qid, wcid, sta, &tx_info); -if (err <0 ) +if (err <0 ) { + status.skb = tx_info.skb; +spin_lock_bh (&dev->rx_lock); +ieee80211_tx_status_ext (dev->hw, &status); +spin_unlock_bh (&dev->rx_lock);return err; + } q->entry[q->head].skb = tx_info.skb; q->entry[q->head].buf_sz = len;
Signature · 1 line
2.53.0