6.19.11-rc1 review
Subsystems (4)
Greg Kroah-Hartman
maintainerPATCH 149/342 RDMA/efa: Improve admin completion context state machine
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yonatan Nachum <[email protected]>
[ Upstream commit dab5825491f7b0ea92a09390f39df0a51100f12f ]
Add a new unused state to the admin completion contexts state machine instead of the occupied field. This improves the completion validity check because it now enforce the context to be in submitted state prior to completing it. Also add allocated state as a intermediate state between unused and submitted.
Stable-dep-of: ef3b06742c8a ("RDMA/efa: Fix use of completion ctx after free")
--- drivers/infiniband/hw/efa/efa_com.c | 91 ++++++++++++++++------------- 1 file changed, 50 insertions(+), 41 deletions(-)
drivers/infiniband/hw/efa/efa_com.c +50 -41
@@ -23,6 +23,8 @@#define EFA_CTRL_SUB_MINOR 1enum efa_cmd_status { +EFA_CMD_UNUSED , +EFA_CMD_ALLOCATED ,EFA_CMD_SUBMITTED ,EFA_CMD_COMPLETED , };
@@ -34,7 +36,6 @@ struct efa_comp_ctx {enum efa_cmd_status status;u16 cmd_id;u8 cmd_opcode; -u8 occupied; };static const char *efa_com_cmd_str (u8 cmd)
@@ -243,7 +244,6 @@ static int efa_com_admin_init_aenq(struct efa_com_dev *edev,return 0 ; } -/* ID to be used with efa_com_get_comp_ctx */ static u16 efa_com_alloc_ctx_id (struct efa_com_admin_queue *aq) {u16 ctx_id;
@@ -265,36 +265,47 @@ static void efa_com_dealloc_ctx_id(struct efa_com_admin_queue *aq,spin_unlock (&aq->comp_ctx_lock); } -static inline void efa_com_put_comp_ctx (struct efa_com_admin_queue *aq, -struct efa_comp_ctx *comp_ctx) +static struct efa_comp_ctx *efa_com_alloc_comp_ctx (struct efa_com_admin_queue *aq) { -u16 cmd_id =EFA_GET (&comp_ctx->user_cqe->acq_common_descriptor.command, -EFA_ADMIN_ACQ_COMMON_DESC_COMMAND_ID ); -u16 ctx_id = cmd_id & (aq->depth -1 ); +struct efa_comp_ctx *comp_ctx; +u16 ctx_id; -ibdev_dbg (aq->efa_dev,"Put completion command_id %#x\n" , cmd_id); - comp_ctx->occupied =0 ; -efa_com_dealloc_ctx_id (aq, ctx_id); + ctx_id =efa_com_alloc_ctx_id (aq); + + comp_ctx = &aq->comp_ctx[ctx_id]; +if (comp_ctx->status !=EFA_CMD_UNUSED ) { +efa_com_dealloc_ctx_id (aq, ctx_id); +ibdev_err_ratelimited (aq->efa_dev, +"Completion context[%u] is used[%u]\n" , + ctx_id, comp_ctx->status); +return NULL ; + } + + comp_ctx->status =EFA_CMD_ALLOCATED ; +ibdev_dbg (aq->efa_dev,"Take completion context[%u]\n" , ctx_id); +return comp_ctx; } -static struct efa_comp_ctx *efa_com_get_comp_ctx (struct efa_com_admin_queue *aq, -u16 cmd_id,bool capture) +static inline u16 efa_com_get_comp_ctx_id (struct efa_com_admin_queue *aq, +struct efa_comp_ctx *comp_ctx) { -u16 ctx_id = cmd_id & (aq->depth -1 ); +return comp_ctx - aq->comp_ctx; +} -if (aq->comp_ctx[ctx_id].occupied && capture) { -ibdev_err_ratelimited ( - aq->efa_dev, -"Completion context for command_id %#x is occupied\n" , - cmd_id); -return NULL ; - } +static inline void efa_com_dealloc_comp_ctx (struct efa_com_admin_queue *aq, +struct efa_comp_ctx *comp_ctx) +{ +u16 ctx_id =efa_com_get_comp_ctx_id (aq, comp_ctx); -if (capture) { - aq->comp_ctx[ctx_id].occupied =1 ; -ibdev_dbg (aq->efa_dev, -"Take completion ctxt for command_id %#x\n" , cmd_id); - } +ibdev_dbg (aq->efa_dev,"Put completion context[%u]\n" , ctx_id); + comp_ctx->status =EFA_CMD_UNUSED ; +efa_com_dealloc_ctx_id (aq, ctx_id); +} + +static inline struct efa_comp_ctx *efa_com_get_comp_ctx_by_cmd_id (struct efa_com_admin_queue *aq, +u16 cmd_id) +{ +u16 ctx_id = cmd_id & (aq->depth -1 );return &aq->comp_ctx[ctx_id]; }
@@ -312,10 +323,13 @@ static struct efa_comp_ctx *__efa_com_submit_admin_cmd(struct efa_com_admin_queuu16 ctx_id;u16 pi; + comp_ctx =efa_com_alloc_comp_ctx (aq); +if (!comp_ctx) +return ERR_PTR (-EINVAL ); + queue_size_mask = aq->depth -1 ; pi = aq->sq.pc & queue_size_mask; - - ctx_id =efa_com_alloc_ctx_id (aq); + ctx_id =efa_com_get_comp_ctx_id (aq, comp_ctx);/* cmd_id LSBs are the ctx_id and MSBs are entropy bits from pc */ cmd_id = ctx_id & queue_size_mask;
@@ -326,12 +340,6 @@ static struct efa_comp_ctx *__efa_com_submit_admin_cmd(struct efa_com_admin_queuEFA_SET (&cmd->aq_common_descriptor.flags,EFA_ADMIN_AQ_COMMON_DESC_PHASE , aq->sq.phase); - comp_ctx =efa_com_get_comp_ctx (aq, cmd_id, true); -if (!comp_ctx) { -efa_com_dealloc_ctx_id (aq, ctx_id); -return ERR_PTR (-EINVAL ); - } - comp_ctx->status =EFA_CMD_SUBMITTED ; comp_ctx->comp_size = comp_size_in_bytes; comp_ctx->user_cqe = comp;
@@ -372,9 +380,9 @@ static inline int efa_com_init_comp_ctxt(struct efa_com_admin_queue *aq) }for (i =0 ; i < aq->depth; i++) { - comp_ctx =efa_com_get_comp_ctx (aq, i, false); -if (comp_ctx) -init_completion (&comp_ctx->wait_event); + comp_ctx = &aq->comp_ctx[i]; + comp_ctx->status =EFA_CMD_UNUSED ; +init_completion (&comp_ctx->wait_event); aq->comp_ctx_pool[i] = i; }
@@ -419,11 +427,12 @@ static int efa_com_handle_single_admin_completion(struct efa_com_admin_queue *aq cmd_id =EFA_GET (&cqe->acq_common_descriptor.command,EFA_ADMIN_ACQ_COMMON_DESC_COMMAND_ID ); - comp_ctx =efa_com_get_comp_ctx (aq, cmd_id, false); + comp_ctx =efa_com_get_comp_ctx_by_cmd_id (aq, cmd_id);if (comp_ctx->status !=EFA_CMD_SUBMITTED || comp_ctx->cmd_id != cmd_id) {ibdev_err (aq->efa_dev, -"Received completion with unexpected command id[%d], sq producer: %d, sq consumer: %d, cq consumer: %d\n" , - cmd_id, aq->sq.pc, aq->sq.cc, aq->cq.cc); +"Received completion with unexpected command id[%x], status[%d] sq producer[%d], sq consumer[%d], cq consumer[%d]\n" , + cmd_id, comp_ctx->status, aq->sq.pc, aq->sq.cc, + aq->cq.cc);return -EINVAL ; }
@@ -532,7 +541,7 @@ static int efa_com_wait_and_process_admin_cq_polling(struct efa_comp_ctx *comp_c err =efa_com_comp_status_to_errno (comp_ctx->user_cqe->acq_common_descriptor.status); out: -efa_com_put_comp_ctx (aq, comp_ctx); +efa_com_dealloc_comp_ctx (aq, comp_ctx);return err; }
@@ -582,7 +591,7 @@ static int efa_com_wait_and_process_admin_cq_interrupts(struct efa_comp_ctx *com err =efa_com_comp_status_to_errno (comp_ctx->user_cqe->acq_common_descriptor.status); out: -efa_com_put_comp_ctx (aq, comp_ctx); +efa_com_dealloc_comp_ctx (aq, comp_ctx);return err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 150/342 RDMA/efa: Fix use of completion ctx after free
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yonatan Nachum <[email protected]>
[ Upstream commit ef3b06742c8a201d0e83edc9a33a89a4fe3009f8 ]
On admin queue completion handling, if the admin command completed with error we print data from the completion context. The issue is that we already freed the completion context in polling/interrupts handler which means we print data from context in an unknown state (it might be already used again).
Change the admin submission flow so alloc/dealloc of the context will be symmetric and dealloc will be called after any potential use of the context.
--- drivers/infiniband/hw/efa/efa_com.c | 87 +++++++++++++---------------- 1 file changed, 39 insertions(+), 48 deletions(-)
drivers/infiniband/hw/efa/efa_com.c +39 -48
@@ -1,6 +1,6 @@// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause /* -* Copyright 2018-2025 Amazon.com, Inc. or its affiliates. All rights reserved. +* Copyright 2018-2026 Amazon.com, Inc. or its affiliates. All rights reserved. */ #include <linux/log2.h>
@@ -310,23 +310,19 @@ static inline struct efa_comp_ctx *efa_com_get_comp_ctx_by_cmd_id(struct efa_comreturn &aq->comp_ctx[ctx_id]; } -static struct efa_comp_ctx *__efa_com_submit_admin_cmd (struct efa_com_admin_queue *aq, -struct efa_admin_aq_entry *cmd, -size_t cmd_size_in_bytes, -struct efa_admin_acq_entry *comp, -size_t comp_size_in_bytes) +static void __efa_com_submit_admin_cmd (struct efa_com_admin_queue *aq, +struct efa_comp_ctx *comp_ctx, +struct efa_admin_aq_entry *cmd, +size_t cmd_size_in_bytes, +struct efa_admin_acq_entry *comp, +size_t comp_size_in_bytes) {struct efa_admin_aq_entry *aqe; -struct efa_comp_ctx *comp_ctx;u16 queue_size_mask;u16 cmd_id;u16 ctx_id;u16 pi; - comp_ctx =efa_com_alloc_comp_ctx (aq); -if (!comp_ctx) -return ERR_PTR (-EINVAL ); - queue_size_mask = aq->depth -1 ; pi = aq->sq.pc & queue_size_mask; ctx_id =efa_com_get_comp_ctx_id (aq, comp_ctx);
@@ -360,8 +356,6 @@ static struct efa_comp_ctx *__efa_com_submit_admin_cmd(struct efa_com_admin_queu/* barrier not needed in case of writel */ writel (aq->sq.pc, aq->sq.db_addr); - -return comp_ctx; }static inline int efa_com_init_comp_ctxt (struct efa_com_admin_queue *aq)
@@ -394,28 +388,25 @@ static inline int efa_com_init_comp_ctxt(struct efa_com_admin_queue *aq)return 0 ; } -static struct efa_comp_ctx *efa_com_submit_admin_cmd (struct efa_com_admin_queue *aq, -struct efa_admin_aq_entry *cmd, -size_t cmd_size_in_bytes, -struct efa_admin_acq_entry *comp, -size_t comp_size_in_bytes) +static int efa_com_submit_admin_cmd (struct efa_com_admin_queue *aq, +struct efa_comp_ctx *comp_ctx, +struct efa_admin_aq_entry *cmd, +size_t cmd_size_in_bytes, +struct efa_admin_acq_entry *comp, +size_t comp_size_in_bytes) { -struct efa_comp_ctx *comp_ctx; -spin_lock (&aq->sq.lock);if (!test_bit (EFA_AQ_STATE_RUNNING_BIT , &aq->state)) {ibdev_err_ratelimited (aq->efa_dev,"Admin queue is closed\n" );spin_unlock (&aq->sq.lock); -return ERR_PTR (-ENODEV ); +return -ENODEV ; } - comp_ctx =__efa_com_submit_admin_cmd (aq, cmd, cmd_size_in_bytes, comp, - comp_size_in_bytes); +__efa_com_submit_admin_cmd (aq, comp_ctx, cmd, cmd_size_in_bytes, comp, + comp_size_in_bytes);spin_unlock (&aq->sq.lock); -if (IS_ERR (comp_ctx)) -clear_bit (EFA_AQ_STATE_RUNNING_BIT , &aq->state); -return comp_ctx; +return 0 ; } static int efa_com_handle_single_admin_completion(struct efa_com_admin_queue *aq,
@@ -512,7 +503,6 @@ static int efa_com_wait_and_process_admin_cq_polling(struct efa_comp_ctx *comp_c {unsigned long timeout;unsigned long flags; -int err; timeout = jiffies +usecs_to_jiffies (aq->completion_timeout);
@@ -532,24 +522,20 @@ static int efa_com_wait_and_process_admin_cq_polling(struct efa_comp_ctx *comp_catomic64_inc (&aq->stats.no_completion);clear_bit (EFA_AQ_STATE_RUNNING_BIT , &aq->state); - err = -ETIME ; - goto out; +return -ETIME ; }msleep (aq->poll_interval); } - err =efa_com_comp_status_to_errno (comp_ctx->user_cqe->acq_common_descriptor.status); -out: -efa_com_dealloc_comp_ctx (aq, comp_ctx); -return err; +return efa_com_comp_status_to_errno ( + comp_ctx->user_cqe->acq_common_descriptor.status); }static int efa_com_wait_and_process_admin_cq_interrupts (struct efa_comp_ctx *comp_ctx,struct efa_com_admin_queue *aq) {unsigned long flags; -int err;wait_for_completion_timeout (&comp_ctx->wait_event,usecs_to_jiffies (aq->completion_timeout));
@@ -585,14 +571,11 @@ static int efa_com_wait_and_process_admin_cq_interrupts(struct efa_comp_ctx *com aq->cq.cc);clear_bit (EFA_AQ_STATE_RUNNING_BIT , &aq->state); - err = -ETIME ; - goto out; +return -ETIME ; } - err =efa_com_comp_status_to_errno (comp_ctx->user_cqe->acq_common_descriptor.status); -out: -efa_com_dealloc_comp_ctx (aq, comp_ctx); -return err; +return efa_com_comp_status_to_errno ( + comp_ctx->user_cqe->acq_common_descriptor.status); }/*
@@ -642,30 +625,38 @@ int efa_com_cmd_exec(struct efa_com_admin_queue *aq,ibdev_dbg (aq->efa_dev,"%s (opcode %d)\n" ,efa_com_cmd_str (cmd->aq_common_descriptor.opcode), cmd->aq_common_descriptor.opcode); - comp_ctx =efa_com_submit_admin_cmd (aq, cmd, cmd_size, comp, comp_size); -if (IS_ERR (comp_ctx)) { + + comp_ctx =efa_com_alloc_comp_ctx (aq); +if (!comp_ctx) { +clear_bit (EFA_AQ_STATE_RUNNING_BIT , &aq->state); +return -EINVAL ; + } + + err =efa_com_submit_admin_cmd (aq, comp_ctx, cmd, cmd_size, comp, comp_size); +if (err) {ibdev_err_ratelimited ( aq->efa_dev, -"Failed to submit command %s (opcode %u) err %pe\n" , +"Failed to submit command %s (opcode %u) err %d\n" ,efa_com_cmd_str (cmd->aq_common_descriptor.opcode), - cmd->aq_common_descriptor.opcode, comp_ctx); + cmd->aq_common_descriptor.opcode, err); +efa_com_dealloc_comp_ctx (aq, comp_ctx);up (&aq->avail_cmds);atomic64_inc (&aq->stats.cmd_err); -return PTR_ERR (comp_ctx); +return err; } err =efa_com_wait_and_process_admin_cq (comp_ctx, aq);if (err) {ibdev_err_ratelimited ( aq->efa_dev, -"Failed to process command %s (opcode %u) comp_status %d err %d\n" , +"Failed to process command %s (opcode %u) err %d\n" ,efa_com_cmd_str (cmd->aq_common_descriptor.opcode), - cmd->aq_common_descriptor.opcode, - comp_ctx->user_cqe->acq_common_descriptor.status, err); + cmd->aq_common_descriptor.opcode, err);atomic64_inc (&aq->stats.cmd_err); } +efa_com_dealloc_comp_ctx (aq, comp_ctx);up (&aq->avail_cmds);return err;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 151/342 regmap: Synchronize cache for the page selector
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andy Shevchenko <[email protected]>
[ Upstream commit 09e70e4f119ff650d24c96161fd2f62ac7e424b0 ]
If the selector register is represented in each page, its value according to the debugfs is stale because it gets synchronized only after the real page switch happens. Hence the regmap cache initialisation from the HW inherits outdated data in the selector register.
Synchronize cache for the page selector just in time.
Before (offset followed by hexdump, the first byte is selector):
// Real registers
18: 05 ff 00 00 ff 0f 00 00 f0 00 00 00
...
// Virtual (per port)
40: 05 ff 00 00 e0 e0 00 00 00 00 00 1f
50: 00 ff 00 00 e0 e0 00 00 00 00 00 1f
60: 01 ff 00 00 ff ff 00 00 00 00 00 00
70: 02 ff 00 00 cf f3 00 00 00 00 00 0c
80: 03 ff 00 00 00 00 00 00 00 00 00 ff
90: 04 ff 00 00 ff 0f 00 00 f0 00 00 00After:
// Real registers
18: 05 ff 00 00 ff 0f 00 00 f0 00 00 00
...
// Virtual (per port)
40: 00 ff 00 00 e0 e0 00 00 00 00 00 1f
50: 01 ff 00 00 e0 e0 00 00 00 00 00 1f
60: 02 ff 00 00 ff ff 00 00 00 00 00 00
70: 03 ff 00 00 cf f3 00 00 00 00 00 0c
80: 04 ff 00 00 00 00 00 00 00 00 00 ff
90: 05 ff 00 00 ff 0f 00 00 f0 00 00 00--- drivers/base/regmap/regmap.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-)
drivers/base/regmap/regmap.c +26 -4
@@ -1543,6 +1543,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg, unsigned int val_num) {void *orig_work_buf; +unsigned int selector_reg;unsigned int win_offset;unsigned int win_page;bool page_chg;
@@ -1561,10 +1562,31 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,return -EINVAL ; } -/* It is possible to have selector register inside data window. -In that case, selector register is located on every page and -it needs no page switching, when accessed alone. */ +/* +* Calculate the address of the selector register in the corresponding +* data window if it is located on every page. +*/ + page_chg =in_range (range->selector_reg, range->window_start, range->window_len); +if (page_chg) + selector_reg = range->range_min + win_page * range->window_len + + range->selector_reg - range->window_start; + +/* +* It is possible to have selector register inside data window. +* In that case, selector register is located on every page and it +* needs no page switching, when accessed alone. +* +* Nevertheless we should synchronize the cache values for it. +* This can't be properly achieved if the selector register is +* the first and the only one to be read inside the data window. +* That's why we update it in that case as well. +* +* However, we specifically avoid updating it for the default page, +* when it's overlapped with the real data window, to prevent from +* infinite looping. +*/ if (val_num >1 || + (page_chg && selector_reg != range->selector_reg) || range->window_start + win_offset != range->selector_reg) {/* Use separate work_buf during page switching */ orig_work_buf = map->work_buf;
@@ -1573,7 +1595,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg, ret =_regmap_update_bits (map, range->selector_reg, range->selector_mask, win_page << range->selector_shift, - &page_chg, false); +NULL , false); map->work_buf = orig_work_buf;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 152/342 ALSA: hda/realtek: Sequence GPIO2 on Star Labs StarFighter
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Rhodes <[email protected]>
[ Upstream commit a6919f2a01f8fbf807b015e5b26aecae7db8117b ]
The initial StarFighter quirk fixed the runtime suspend pop by muting speakers in the shutup callback before power-down. Further hardware validation showed that the speaker path is controlled directly by LINE2 EAPD on NID 0x1b together with GPIO2 for the external amplifier.
Replace the shutup-delay workaround with explicit sequencing of those controls at playback start and stop:
- assert LINE2 EAPD and drive GPIO2 high on PREPARE
- deassert LINE2 EAPD and drive GPIO2 low on CLEANUP
This avoids the runtime suspend pop without a sleep, and also fixes pops around G3 entry and display-manager start that the original workaround did not cover.
--- sound/hda/codecs/realtek/alc269.c | 38 ++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 6 deletions(-)
sound/hda/codecs/realtek/alc269.c +32 -6
@@ -1017,12 +1017,30 @@ static int alc269_resume(struct hda_codec *codec)return 0 ; } -#define STARLABS_STARFIGHTER_SHUTUP_DELAY_MS 30 +#define ALC233_STARFIGHTER_SPK_PIN 0x1b +#define ALC233_STARFIGHTER_GPIO2 0x04 -static void starlabs_starfighter_shutup (struct hda_codec *codec) +static void alc233_starfighter_update_amp (struct hda_codec *codec,bool on) { -if (snd_hda_gen_shutup_speakers (codec)) -msleep (STARLABS_STARFIGHTER_SHUTUP_DELAY_MS ); +snd_hda_codec_write (codec,ALC233_STARFIGHTER_SPK_PIN ,0 , +AC_VERB_SET_EAPD_BTLENABLE , + on ?AC_EAPDBTL_EAPD :0 ); +alc_update_gpio_data (codec,ALC233_STARFIGHTER_GPIO2 , on); +} + +static void alc233_starfighter_pcm_hook (struct hda_pcm_stream *hinfo, +struct hda_codec *codec, +struct snd_pcm_substream *substream, +int action) +{ +switch (action) { +case HDA_GEN_PCM_ACT_PREPARE : +alc233_starfighter_update_amp (codec, true); +break ; +case HDA_GEN_PCM_ACT_CLEANUP : +alc233_starfighter_update_amp (codec, false); +break ; + } } static void alc233_fixup_starlabs_starfighter(struct hda_codec *codec,
@@ -1031,8 +1049,16 @@ static void alc233_fixup_starlabs_starfighter(struct hda_codec *codec, {struct alc_spec *spec = codec->spec; -if (action ==HDA_FIXUP_ACT_PRE_PROBE ) - spec->shutup = starlabs_starfighter_shutup; +switch (action) { +case HDA_FIXUP_ACT_PRE_PROBE : + spec->gpio_mask |=ALC233_STARFIGHTER_GPIO2 ; + spec->gpio_dir |=ALC233_STARFIGHTER_GPIO2 ; + spec->gpio_data &= ~ALC233_STARFIGHTER_GPIO2 ; +break ; +case HDA_FIXUP_ACT_PROBE : + spec->gen.pcm_playback_hook = alc233_starfighter_pcm_hook; +break ; + } } static void alc269_fixup_pincfg_no_hp_to_lineout(struct hda_codec *codec,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 153/342 RDMA/rw: Fall back to direct SGE on MR pool exhaustion
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 00da250c21b074ea9494c375d0117b69e5b1d0a4 ]
When IOMMU passthrough mode is active, ib_dma_map_sgtable_attrs() produces no coalescing: each scatterlist page maps 1:1 to a DMA entry, so sgt.nents equals the raw page count. A 1 MB transfer yields 256 DMA entries. If that count exceeds the device's max_sgl_rd threshold (an optimization hint from mlx5 firmware), rdma_rw_io_needs_mr() steers the operation into the MR registration path. Each such operation consumes one or more MRs from a pool sized at max_rdma_ctxs -- roughly one MR per concurrent context. Under write-intensive workloads that issue many concurrent RDMA READs, the pool is rapidly exhausted, ib_mr_pool_get() returns NULL, and rdma_rw_init_one_mr() returns -EAGAIN. Upper layer protocols treat this as a fatal DMA mapping failure and tear down the connection.
The max_sgl_rd check is a performance optimization, not a correctness requirement: the device can handle large SGE counts via direct posting, just less efficiently than with MR registration. When the MR pool cannot satisfy a request, falling back to the direct SGE (map_wrs) path avoids the connection reset while preserving the MR optimization for the common case where pool resources are available.
Add a fallback in rdma_rw_ctx_init() so that -EAGAIN from rdma_rw_init_mr_wrs() triggers direct SGE posting instead of propagating the error. iWARP devices, which mandate MR registration for RDMA READs, and force_mr debug mode continue to treat -EAGAIN as terminal.
--- drivers/infiniband/core/rw.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-)
drivers/infiniband/core/rw.c +18 -3
@@ -326,14 +326,29 @@ int rdma_rw_ctx_init(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u32 port_num,if (rdma_rw_io_needs_mr (qp->device, port_num, dir, sg_cnt)) { ret =rdma_rw_init_mr_wrs (ctx, qp, port_num, sg, sg_cnt, sg_offset, remote_addr, rkey, dir); - }else if (sg_cnt >1 ) { +/* +* If MR init succeeded or failed for a reason other +* than pool exhaustion, that result is final. +* +* Pool exhaustion (-EAGAIN) from the max_sgl_rd +* optimization is recoverable: fall back to +* direct SGE posting. iWARP and force_mr require +* MRs unconditionally, so -EAGAIN is terminal. +*/ +if (ret != -EAGAIN || +rdma_protocol_iwarp (qp->device, port_num) || +unlikely (rdma_rw_force_mr)) + goto out; + } + +if (sg_cnt >1 ) ret =rdma_rw_init_map_wrs (ctx, qp, sg, sg_cnt, sg_offset, remote_addr, rkey, dir); - }else { +else ret =rdma_rw_init_single_wr (ctx, qp, sg, sg_offset, remote_addr, rkey, dir); - } +out:if (ret <0 ) goto out_unmap_sg;return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 154/342 RDMA/efa: Fix possible deadlock
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ethan Tidmore <[email protected]>
[ Upstream commit 0f2055db7b630559870afb40fc84490816ab8ec5 ]
In the error path for efa_com_alloc_comp_ctx() the semaphore assigned to &aq->avail_cmds is not released.
Detected by Smatch:drivers/infiniband/hw/efa/efa_com.c:662 efa_com_cmd_exec() warn:
inconsistent returns '&aq->avail_cmds'
Add release for &aq->avail_cmds in efa_com_alloc_comp_ctx() error path.
--- drivers/infiniband/hw/efa/efa_com.c | 1 + 1 file changed, 1 insertion(+)
drivers/infiniband/hw/efa/efa_com.c +1 -0
@@ -629,6 +629,7 @@ int efa_com_cmd_exec(struct efa_com_admin_queue *aq, comp_ctx =efa_com_alloc_comp_ctx (aq);if (!comp_ctx) {clear_bit (EFA_AQ_STATE_RUNNING_BIT , &aq->state); +up (&aq->avail_cmds);return -EINVAL ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 155/342 ALSA: usb-audio: Exclude Scarlett 2i2 1st Gen from SKIP_IFACE_SETUP
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Geoffrey D. Bennett <[email protected]>
[ Upstream commit 8780f561f6717dec52351251881bff79e960eb46 ]
The Focusrite Scarlett 2i2 1st Gen (1235:8006) produces distorted/silent audio when QUIRK_FLAG_SKIP_IFACE_SETUP is active, as that flag causes the feedback format to be detected as 17.15 instead of 16.16.
Add a DEVICE_FLG entry for this device before the Focusrite VENDOR_FLG entry so that it gets no quirk flags, overriding the vendor-wide SKIP_IFACE_SETUP. This device doesn't have the internal mixer, Air, or Safe modes that the quirk was designed to protect.
--- sound/usb/quirks.c | 1 + 1 file changed, 1 insertion(+)
sound/usb/quirks.c +1 -0
@@ -2425,6 +2425,7 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { QUIRK_FLAG_CTL_MSG_DELAY | QUIRK_FLAG_IFACE_DELAY),VENDOR_FLG (0x07fd ,/* MOTU */ QUIRK_FLAG_VALIDATE_RATES ), +DEVICE_FLG (0x1235 ,0x8006 ,0 ),/* Focusrite Scarlett 2i2 1st Gen */ VENDOR_FLG (0x1235 ,/* Focusrite Novation */ QUIRK_FLAG_SKIP_IFACE_SETUP ), VENDOR_FLG(0x1511, /* AURALiC */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 156/342 RDMA/irdma: Initialize free_qp completion before using it
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jacob Moroni <[email protected]>
[ Upstream commit 11a95521fb93c91e2d4ef9d53dc80ef0a755549b ]
In irdma_create_qp, if ib_copy_to_udata fails, it will call irdma_destroy_qp to clean up which will attempt to wait on the free_qp completion, which is not initialized yet. Fix this by initializing the completion before the ib_copy_to_udata call.
--- drivers/infiniband/hw/irdma/verbs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/infiniband/hw/irdma/verbs.c +1 -1
@@ -1105,6 +1105,7 @@ static int irdma_create_qp(struct ib_qp *ibqp,spin_lock_init (&iwqp->sc_qp.pfpdu.lock); iwqp->sig_all = init_attr->sq_sig_type ==IB_SIGNAL_ALL_WR ; rf->qp_table[qp_num] = iwqp; +init_completion (&iwqp->free_qp);if (udata) {/* GEN_1 legacy support with libi40iw does not have expanded uresp struct */
@@ -1129,7 +1130,6 @@ static int irdma_create_qp(struct ib_qp *ibqp, } } -init_completion (&iwqp->free_qp);return 0 ; error:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 157/342 RDMA/irdma: Update ibqp state to error if QP is already in error state
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tatyana Nikolova <[email protected]>
[ Upstream commit 8c1f19a2225cf37b3f8ab0b5a8a5322291cda620 ]
In irdma_modify_qp() update ibqp state to error if the irdma QP is already in error state, otherwise the ibqp state which is visible to the consumer app remains stale.
--- drivers/infiniband/hw/irdma/verbs.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/infiniband/hw/irdma/verbs.c +2 -0
@@ -1540,6 +1540,7 @@ int irdma_modify_qp_roce(struct ib_qp *ibqp, struct ib_qp_attr *attr,case IB_QPS_ERR :case IB_QPS_RESET :if (iwqp->iwarp_state ==IRDMA_QP_STATE_ERROR ) { + iwqp->ibqp_state = attr->qp_state;spin_unlock_irqrestore (&iwqp->lock, flags);if (udata && udata->inlen) { if (ib_copy_from_udata(&ureq, udata,
@@ -1745,6 +1746,7 @@ int irdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,case IB_QPS_ERR :case IB_QPS_RESET :if (iwqp->iwarp_state ==IRDMA_QP_STATE_ERROR ) { + iwqp->ibqp_state = attr->qp_state;spin_unlock_irqrestore (&iwqp->lock, flags);if (udata && udata->inlen) { if (ib_copy_from_udata(&ureq, udata,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 158/342 RDMA/irdma: Remove a NOP wait_event() in irdma_modify_qp_roce()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tatyana Nikolova <[email protected]>
[ Upstream commit 5e8f0239731a83753473b7aa91bda67bbdff5053 ]
Remove a NOP wait_event() in irdma_modify_qp_roce() which is relevant for iWARP and likely a copy and paste artifact for RoCEv2. The wait event is for sending a reset on a TCP connection, after the reset has been requested in irdma_modify_qp(), which occurs only in iWarp mode.
--- drivers/infiniband/hw/irdma/verbs.c | 2 -- 1 file changed, 2 deletions(-)
drivers/infiniband/hw/irdma/verbs.c +0 -2
@@ -1462,8 +1462,6 @@ int irdma_modify_qp_roce(struct ib_qp *ibqp, struct ib_qp_attr *attr, ctx_info->remote_atomics_en = true; } -wait_event (iwqp->mod_qp_waitq, !atomic_read (&iwqp->hw_mod_qp_pend)); - ibdev_dbg(&iwdev->ibdev, "VERBS: caller: %pS qp_id=%d to_ibqpstate=%d ibqpstate=%d irdma_qpstate=%d attr_mask=0x%x\n", __builtin_return_address(0), ibqp->qp_num, attr->qp_state,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 159/342 RDMA/irdma: Clean up unnecessary dereference of event->cm_node
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ivan Barrera <[email protected]>
[ Upstream commit b415399c9a024d574b65479636f0d4eb625b9abd ]
The cm_node is available and the usage of cm_node and event->cm_node seems arbitrary. Clean up unnecessary dereference of event->cm_node.
--- drivers/infiniband/hw/irdma/cm.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/infiniband/hw/irdma/cm.c +6 -6
@@ -4239,21 +4239,21 @@ static void irdma_cm_event_handler(struct work_struct *work)irdma_cm_event_reset (event);break ;case IRDMA_CM_EVENT_CONNECTED : -if (!event->cm_node->cm_id || - event->cm_node->state !=IRDMA_CM_STATE_OFFLOADED ) +if (!cm_node->cm_id || + cm_node->state !=IRDMA_CM_STATE_OFFLOADED )break ;irdma_cm_event_connected (event);break ;case IRDMA_CM_EVENT_MPA_REJECT : -if (!event->cm_node->cm_id || +if (!cm_node->cm_id || cm_node->state ==IRDMA_CM_STATE_OFFLOADED )break ;irdma_send_cm_event (cm_node, cm_node->cm_id,IW_CM_EVENT_CONNECT_REPLY , -ECONNREFUSED );break ;case IRDMA_CM_EVENT_ABORTED : -if (!event->cm_node->cm_id || - event->cm_node->state ==IRDMA_CM_STATE_OFFLOADED ) +if (!cm_node->cm_id || + cm_node->state ==IRDMA_CM_STATE_OFFLOADED )break ;irdma_event_connect_error (event);break ;
@@ -4263,7 +4263,7 @@ static void irdma_cm_event_handler(struct work_struct *work)break ; } -irdma_rem_ref_cm_node (event->cm_node); +irdma_rem_ref_cm_node (cm_node);kfree (event); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 160/342 RDMA/irdma: Remove reset check from irdma_modify_qp_to_err()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tatyana Nikolova <[email protected]>
[ Upstream commit c45c6ebd693b944f1ffe429fdfb6cc1674c237be ]
During reset, irdma_modify_qp() to error should be called to disconnect the QP. Without this fix, if not preceded by irdma_modify_qp() to error, the API call irdma_destroy_qp() gets stuck waiting for the QP refcount to go to zero, because the cm_node associated with this QP isn't disconnected.
--- drivers/infiniband/hw/irdma/utils.c | 2 -- 1 file changed, 2 deletions(-)
drivers/infiniband/hw/irdma/utils.c +0 -2
@@ -2321,8 +2321,6 @@ void irdma_modify_qp_to_err(struct irdma_sc_qp *sc_qp)struct irdma_qp *qp = sc_qp->qp_uk.back_qp;struct ib_qp_attr attr; -if (qp->iwdev->rf->reset) -return ; attr.qp_state =IB_QPS_ERR ;if (rdma_protocol_roce (qp->ibqp.device,1 ))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 161/342 RDMA/irdma: Fix deadlock during netdev reset with active connections
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anil Samal <[email protected]>
[ Upstream commit 6f52370970ac07d352a7af4089e55e0e6425f827 ]
Resolve deadlock that occurs when user executes netdev reset while RDMA applications (e.g., rping) are active. The netdev reset causes ice driver to remove irdma auxiliary driver, triggering device_delete and subsequent client removal. During client removal, uverbs_client waits for QP reference count to reach zero while cma_client holds the final reference, creating circular dependency and indefinite wait in iWARP mode. Skip QP reference count wait during device reset to prevent deadlock.
--- drivers/infiniband/hw/irdma/verbs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/infiniband/hw/irdma/verbs.c +2 -1
@@ -558,7 +558,8 @@ static int irdma_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata) }irdma_qp_rem_ref (&iwqp->ibqp); -wait_for_completion (&iwqp->free_qp); +if (!iwdev->rf->reset) +wait_for_completion (&iwqp->free_qp);irdma_free_lsmm_rsrc (iwqp);irdma_cqp_qp_destroy_cmd (&iwdev->rf->sc_dev, &iwqp->sc_qp);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 162/342 RDMA/irdma: Return EINVAL for invalid arp index error
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tatyana Nikolova <[email protected]>
[ Upstream commit 7221f581eefa79ead06e171044f393fb7ee22f87 ]
When rdma_connect() fails due to an invalid arp index, user space rdma core reports ENOMEM which is confusing. Modify irdma_make_cm_node() to return the correct error code.
--- drivers/infiniband/hw/irdma/cm.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-)
drivers/infiniband/hw/irdma/cm.c +10 -7
@@ -2241,11 +2241,12 @@ irdma_make_cm_node(struct irdma_cm_core *cm_core, struct irdma_device *iwdev,int oldarpindex;int arpindex;struct net_device *netdev = iwdev->netdev; +int ret;/* create an hte and cm_node for this instance */ cm_node =kzalloc (sizeof (*cm_node),GFP_ATOMIC );if (!cm_node) -return NULL ; +return ERR_PTR (-ENOMEM );/* set our node specific transport info */ cm_node->ipv4 = cm_info->ipv4;
@@ -2348,8 +2349,10 @@ irdma_make_cm_node(struct irdma_cm_core *cm_core, struct irdma_device *iwdev, arpindex = -EINVAL ; } -if (arpindex <0 ) +if (arpindex <0 ) { + ret = -EINVAL ; goto err; + }ether_addr_copy (cm_node->rem_mac, iwdev->rf->arp_table[arpindex].mac_addr);
@@ -2360,7 +2363,7 @@ irdma_make_cm_node(struct irdma_cm_core *cm_core, struct irdma_device *iwdev, err:kfree (cm_node); -return NULL ; +return ERR_PTR (ret); }static void irdma_destroy_connection (struct irdma_cm_node *cm_node)
@@ -3021,8 +3024,8 @@ static int irdma_create_cm_node(struct irdma_cm_core *cm_core,/* create a CM connection node */ cm_node =irdma_make_cm_node (cm_core, iwdev, cm_info,NULL ); -if (!cm_node) -return -ENOMEM ; +if (IS_ERR (cm_node)) +return PTR_ERR (cm_node);/* set our node side to client (active) side */ cm_node->tcp_cntxt.client =1 ;
@@ -3219,9 +3222,9 @@ void irdma_receive_ilq(struct irdma_sc_vsi *vsi, struct irdma_puda_buf *rbuf) cm_info.cm_id = listener->cm_id; cm_node =irdma_make_cm_node (cm_core, iwdev, &cm_info, listener); -if (!cm_node) { +if (IS_ERR (cm_node)) {ibdev_dbg (&cm_core->iwdev->ibdev, -"CM: allocate node failed\n" ); +"CM: allocate node failed ret=%ld\n" ,PTR_ERR (cm_node));refcount_dec (&listener->refcnt);return ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 163/342 RDMA/irdma: Harden depth calculation functions
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shiraz Saleem <[email protected]>
[ Upstream commit e37afcb56ae070477741fe2d6e61fc0c542cce2d ]
An issue was exposed where OS can pass in U32_MAX for SQ/RQ/SRQ size. This can cause integer overflow and truncation of SQ/RQ/SRQ depth returning a success when it should have failed.
Harden the functions to do all depth calculations and boundary checking in u64 sizes.
--- drivers/infiniband/hw/irdma/uk.c | 39 ++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 17 deletions(-)
drivers/infiniband/hw/irdma/uk.c +22 -17
@@ -1442,7 +1442,7 @@ int irdma_uk_cq_poll_cmpl(struct irdma_cq_uk *cq,* irdma_round_up_wq - return round up qp wq depth * @wqdepth: wq depth in quanta to round up */ -static int irdma_round_up_wq (u32 wqdepth) +static u64 irdma_round_up_wq (u64 wqdepth) {int scount =1 ;
@@ -1495,15 +1495,16 @@ void irdma_get_wqe_shift(struct irdma_uk_attrs *uk_attrs, u32 sge,int irdma_get_sqdepth (struct irdma_uk_attrs *uk_attrs,u32 sq_size,u8 shift,u32 *sqdepth) { -u32 min_size = (u32 )uk_attrs->min_hw_wq_size << shift; +u32 min_hw_quanta = (u32 )uk_attrs->min_hw_wq_size << shift; +u64 hw_quanta = +irdma_round_up_wq (((u64 )sq_size << shift) +IRDMA_SQ_RSVD ); - *sqdepth =irdma_round_up_wq ((sq_size << shift) +IRDMA_SQ_RSVD ); - -if (*sqdepth < min_size) - *sqdepth = min_size; -else if (*sqdepth > uk_attrs->max_hw_wq_quanta) +if (hw_quanta < min_hw_quanta) + hw_quanta = min_hw_quanta; +else if (hw_quanta > uk_attrs->max_hw_wq_quanta)return -EINVAL ; + *sqdepth = hw_quanta;return 0 ; }
@@ -1517,15 +1518,16 @@ int irdma_get_sqdepth(struct irdma_uk_attrs *uk_attrs, u32 sq_size, u8 shift,int irdma_get_rqdepth (struct irdma_uk_attrs *uk_attrs,u32 rq_size,u8 shift,u32 *rqdepth) { -u32 min_size = (u32 )uk_attrs->min_hw_wq_size << shift; - - *rqdepth =irdma_round_up_wq ((rq_size << shift) +IRDMA_RQ_RSVD ); +u32 min_hw_quanta = (u32 )uk_attrs->min_hw_wq_size << shift; +u64 hw_quanta = +irdma_round_up_wq (((u64 )rq_size << shift) +IRDMA_RQ_RSVD ); -if (*rqdepth < min_size) - *rqdepth = min_size; -else if (*rqdepth > uk_attrs->max_hw_rq_quanta) +if (hw_quanta < min_hw_quanta) + hw_quanta = min_hw_quanta; +else if (hw_quanta > uk_attrs->max_hw_rq_quanta)return -EINVAL ; + *rqdepth = hw_quanta;return 0 ; }
@@ -1539,13 +1541,16 @@ int irdma_get_rqdepth(struct irdma_uk_attrs *uk_attrs, u32 rq_size, u8 shift,int irdma_get_srqdepth (struct irdma_uk_attrs *uk_attrs,u32 srq_size,u8 shift,u32 *srqdepth) { - *srqdepth =irdma_round_up_wq ((srq_size << shift) +IRDMA_RQ_RSVD ); +u32 min_hw_quanta = (u32 )uk_attrs->min_hw_wq_size << shift; +u64 hw_quanta = +irdma_round_up_wq (((u64 )srq_size << shift) +IRDMA_RQ_RSVD ); -if (*srqdepth < ((u32 )uk_attrs->min_hw_wq_size << shift)) - *srqdepth = uk_attrs->min_hw_wq_size << shift; -else if (*srqdepth > uk_attrs->max_hw_srq_quanta) +if (hw_quanta < min_hw_quanta) + hw_quanta = min_hw_quanta; +else if (hw_quanta > uk_attrs->max_hw_srq_quanta)return -EINVAL ; + *srqdepth = hw_quanta;return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 164/342 ASoC: simple-card-utils: Check value of is_playback_only and is_capture_only
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shengjiu Wang <[email protected]>
[ Upstream commit 0e9fc79132ce7ea1e48c388b864382aa38eb0ed4 ]
The audio-graph-card2 gets the value of 'playback-only' and 'capture_only' property in below sequence, if there is 'playback_only' or 'capture_only' property in port_cpu and port_codec nodes, but no these properties in ep_cpu and ep_codec nodes, the value of playback_only and capture_only will be flushed to zero in the end.
graph_util_parse_link_direction(lnk, &playback_only, &capture_only); graph_util_parse_link_direction(ports_cpu, &playback_only, &capture_only); graph_util_parse_link_direction(ports_codec, &playback_only, &capture_only); graph_util_parse_link_direction(port_cpu, &playback_only, &capture_only); graph_util_parse_link_direction(port_codec, &playback_only, &capture_only); graph_util_parse_link_direction(ep_cpu, &playback_only, &capture_only); graph_util_parse_link_direction(ep_codec, &playback_only, &capture_only);
So check the value of is_playback_only and is_capture_only in graph_util_parse_link_direction() function, if they are true, then rewrite the values, and no need to check the np variable as of_property_read_bool() will ignore if it was NULL.
--- sound/soc/generic/simple-card-utils.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
sound/soc/generic/simple-card-utils.c +2 -2
@@ -1183,9 +1183,9 @@ void graph_util_parse_link_direction(struct device_node *np,bool is_playback_only =of_property_read_bool (np,"playback-only" );bool is_capture_only =of_property_read_bool (np,"capture-only" ); -if (np && playback_only) +if (playback_only && is_playback_only) *playback_only = is_playback_only; -if (np && capture_only) +if (capture_only && is_capture_only) *capture_only = is_capture_only; }EXPORT_SYMBOL_GPL (graph_util_parse_link_direction);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 165/342 ASoC: fsl: imx-card: initialize playback_only and capture_only
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shengjiu Wang <[email protected]>
[ Upstream commit ca67bd564e94aaa898a2cbb90922ca3cccd0612b ]
Fix uninitialized variable playback_only and capture_only because graph_util_parse_link_direction() may not write them.
--- sound/soc/fsl/imx-card.c | 2 ++ 1 file changed, 2 insertions(+)
sound/soc/fsl/imx-card.c +2 -0
@@ -710,6 +710,8 @@ static int imx_card_parse_of(struct imx_card_data *data) link->ops = &imx_aif_ops; } + playback_only = false; + capture_only = false;graph_util_parse_link_direction (np, &playback_only, &capture_only); link->playback_only = playback_only; link->capture_only = capture_only;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 166/342 scsi: scsi_transport_sas: Fix the maximum channel scanning issue
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yihang Li <[email protected]>
[ Upstream commit d71afa9deb4d413232ba16d693f7d43b321931b4 ]
After commit 37c4e72b0651 ("scsi: Fix sas_user_scan() to handle wildcard and multi-channel scans"), if the device supports multiple channels (0 to shost->max_channel), user_scan() invokes updated sas_user_scan() to perform the scan behavior for a specific transfer. However, when the user specifies shost->max_channel, it will return -EINVAL, which is not expected.
Fix and support specifying the scan shost->max_channel for scanning.
--- drivers/scsi/scsi_transport_sas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/scsi/scsi_transport_sas.c +1 -1
@@ -1734,7 +1734,7 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel,break ;default : -if (channel < shost->max_channel) { +if (channel <= shost->max_channel) { res =scsi_scan_host_selected (shost, channel, id, lun,SCSI_SCAN_MANUAL ); }else {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 167/342 x86/efi: efi_unmap_boot_services: fix calculation of ranges_to_free size
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mike Rapoport (Microsoft) <[email protected]>
[ Upstream commit 217c0a5c177a3d4f7c8497950cbf5c36756e8bbb ]
ranges_to_free array should have enough room to store the entire EFI memmap plus an extra element for NULL entry.
The calculation of this array size wrongly adds 1 to the overall size instead of adding 1 to the number of elements.
Add parentheses to properly size the array.
--- arch/x86/platform/efi/quirks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/platform/efi/quirks.c +1 -1
@@ -424,7 +424,7 @@ void __init efi_unmap_boot_services(void)if (efi_enabled (EFI_DBG ))return ; - sz =sizeof (*ranges_to_free) * efi.memmap.nr_map +1 ; + sz =sizeof (*ranges_to_free) * (efi.memmap.nr_map +1 ); ranges_to_free =kzalloc (sz,GFP_KERNEL );if (!ranges_to_free) {pr_err ("Failed to allocate storage for freeable EFI regions\n" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 168/342 drm/mediatek: dsi: Store driver data before invoking mipi_dsi_host_register
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luca Leonardo Scorcia <[email protected]>
[ Upstream commit 4cfdfeb6ac06079f92fccd977fa742d6c5b8dd3a ]
The call to mipi_dsi_host_register triggers a callback to mtk_dsi_bind, which uses dev_get_drvdata to retrieve the mtk_dsi struct, so this structure needs to be stored inside the driver data before invoking it.
As drvdata is currently uninitialized it leads to a crash when registering the DSI DRM encoder right after acquiring the mode_config.idr_mutex, blocking all subsequent DRM operations.
Fixes the following crash during mediatek-drm probe (tested on Xiaomi Smart Clock x04g):
Unable to handle kernel NULL pointer dereference at virtual address 0000000000000040 [...] Modules linked in: mediatek_drm(+) drm_display_helper cec drm_client_lib drm_dma_helper drm_kms_helper panel_simple [...] Call trace: drm_mode_object_add+0x58/0x98 (P) __drm_encoder_init+0x48/0x140 drm_encoder_init+0x6c/0xa0 drm_simple_encoder_init+0x20/0x34 [drm_kms_helper] mtk_dsi_bind+0x34/0x13c [mediatek_drm] component_bind_all+0x120/0x280 mtk_drm_bind+0x284/0x67c [mediatek_drm] try_to_bring_up_aggregate_device+0x23c/0x320 __component_add+0xa4/0x198 component_add+0x14/0x20 mtk_dsi_host_attach+0x78/0x100 [mediatek_drm] mipi_dsi_attach+0x2c/0x50 panel_simple_dsi_probe+0x4c/0x9c [panel_simple] mipi_dsi_drv_probe+0x1c/0x28 really_probe+0xc0/0x3dc __driver_probe_device+0x80/0x160 driver_probe_device+0x40/0x120 __device_attach_driver+0xbc/0x17c bus_for_each_drv+0x88/0xf0 __device_attach+0x9c/0x1cc device_initial_probe+0x54/0x60 bus_probe_device+0x34/0xa0 device_add+0x5b0/0x800 mipi_dsi_device_register_full+0xdc/0x16c mipi_dsi_host_register+0xc4/0x17c mtk_dsi_probe+0x10c/0x260 [mediatek_drm] platform_probe+0x5c/0xa4 really_probe+0xc0/0x3dc __driver_probe_device+0x80/0x160 driver_probe_device+0x40/0x120 __driver_attach+0xc8/0x1f8 bus_for_each_dev+0x7c/0xe0 driver_attach+0x24/0x30 bus_add_driver+0x11c/0x240 driver_register+0x68/0x130 __platform_register_drivers+0x64/0x160 mtk_drm_init+0x24/0x1000 [mediatek_drm] do_one_initcall+0x60/0x1d0 do_init_module+0x54/0x240 load_module+0x1838/0x1dc0 init_module_from_file+0xd8/0xf0 __arm64_sys_finit_module+0x1b4/0x428 invoke_syscall.constprop.0+0x48/0xc8 do_el0_svc+0x3c/0xb8 el0_svc+0x34/0xe8 el0t_64_sync_handler+0xa0/0xe4 el0t_64_sync+0x198/0x19c Code: 52800022 941004ab 2a0003f3 37f80040 (29005a80)
--- drivers/gpu/drm/mediatek/mtk_dsi.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
drivers/gpu/drm/mediatek/mtk_dsi.c +5 -4
@@ -1232,6 +1232,11 @@ static int mtk_dsi_probe(struct platform_device *pdev) dsi->host.ops = &mtk_dsi_ops; dsi->host.dev = dev; + +init_waitqueue_head (&dsi->irq_wait_queue); + +platform_set_drvdata (pdev, dsi); + ret =mipi_dsi_host_register (&dsi->host);if (ret <0 )return dev_err_probe (dev, ret,"Failed to register DSI host\n" );
@@ -1243,10 +1248,6 @@ static int mtk_dsi_probe(struct platform_device *pdev)return dev_err_probe (&pdev->dev, ret,"Failed to request DSI irq\n" ); } -init_waitqueue_head (&dsi->irq_wait_queue); - -platform_set_drvdata (pdev, dsi); - dsi->bridge.of_node = dev->of_node; dsi->bridge.type =DRM_MODE_CONNECTOR_DSI ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 169/342 drm/i915/gmbus: fix spurious timeout on 512-byte burst reads
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Samasth Norway Ananda <[email protected]>
[ Upstream commit 08441f10f4dc09fdeb64529953ac308abc79dd38 ]
When reading exactly 512 bytes with burst read enabled, the extra_byte_added path breaks out of the inner do-while without decrementing len. The outer while(len) then re-enters and gmbus_wait() times out since all data has been delivered. Decrement len before the break so the outer loop terminates correctly.
--- drivers/gpu/drm/i915/display/intel_gmbus.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/gpu/drm/i915/display/intel_gmbus.c +3 -1
@@ -498,8 +498,10 @@ gmbus_xfer_read_chunk(struct intel_display *display, val =intel_de_read_fw (display,GMBUS3 (display)); do { - if (extra_byte_added && len == 1) + if (extra_byte_added && len == 1) { + len--; break; + } *buf++ = val & 0xff; val >>= 8;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 170/342 PM: hibernate: Drain trailing zero pages on userspace restore
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alberto Garcia <[email protected]>
[ Upstream commit 734eba62cd32cb9ceffa09e57cdc03d761528525 ]
Commit 005e8dddd497 ("PM: hibernate: don't store zero pages in the image file") added an optimization to skip zero-filled pages in the hibernation image. On restore, zero pages are handled internally by snapshot_write_next() in a loop that processes them without returning to the caller.
With the userspace restore interface, writing the last non-zero page to /dev/snapshot is followed by the SNAPSHOT_ATOMIC_RESTORE ioctl. At this point there are no more calls to snapshot_write_next() so any trailing zero pages are not processed, snapshot_image_loaded() fails because handle->cur is smaller than expected, the ioctl returns -EPERM and the image is not restored.
The in-kernel restore path is not affected by this because the loop in load_image() in swap.c calls snapshot_write_next() until it returns 0. It is this final call that drains any trailing zero pages.
Fixed by calling snapshot_write_next() in snapshot_write_finalize(), giving the kernel the chance to drain any trailing zero pages.
--- kernel/power/snapshot.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
kernel/power/snapshot.c +11 -0
@@ -2855,6 +2855,17 @@ int snapshot_write_finalize(struct snapshot_handle *handle) {int error; +/* +* Call snapshot_write_next() to drain any trailing zero pages, +* but make sure we're in the data page region first. +* This function can return PAGE_SIZE if the kernel was expecting +* another copy page. Return -ENODATA in that situation. +*/ +if (handle->cur > nr_meta_pages +1 ) { + error =snapshot_write_next (handle); +if (error) +return error >0 ? -ENODATA : error; + }copy_last_highmem_page (); error =hibernate_restore_protect_page (handle->buffer);/* Do that only if we have loaded the image entirely */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 171/342 PM: sleep: Drop spurious WARN_ON() from pm_restore_gfp_mask()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Youngjun Park <[email protected]>
[ Upstream commit a8d51efb5929ae308895455a3e496b5eca2cd143 ]
Commit 35e4a69b2003f ("PM: sleep: Allow pm_restrict_gfp_mask() stacking") introduced refcount-based GFP mask management that warns when pm_restore_gfp_mask() is called with saved_gfp_count == 0.
Some hibernation paths call pm_restore_gfp_mask() defensively where the GFP mask may or may not be restricted depending on the execution path. For example, the uswsusp interface invokes it in SNAPSHOT_CREATE_IMAGE, SNAPSHOT_UNFREEZE, and snapshot_release(). Before the stacking change this was a silent no-op; it now triggers a spurious WARNING.
Remove the WARN_ON() wrapper from the !saved_gfp_count check while retaining the check itself, so that defensive calls remain harmless without producing false warnings.
--- kernel/power/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/power/main.c +1 -1
@@ -40,7 +40,7 @@ void pm_restore_gfp_mask(void) {WARN_ON (!mutex_is_locked (&system_transition_mutex)); -if (WARN_ON (!saved_gfp_count) || --saved_gfp_count) +if (!saved_gfp_count || --saved_gfp_count)return ; gfp_allowed_mask = saved_gfp_mask;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 172/342 drm/xe/pf: Fix use-after-free in migration restore
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michał Winiarski <[email protected]>
[ Upstream commit 87997b6c6516e049cbaf2fc6810b213d587a06b1 ]
When an error is returned from xe_sriov_pf_migration_restore_produce(), the data pointer is not set to NULL, which can trigger use-after-free in subsequent .write() calls.
Set the pointer to NULL upon error to fix the problem.
--- drivers/gpu/drm/xe/xe_sriov_packet.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/xe/xe_sriov_packet.c +2 -0
@@ -342,6 +342,8 @@ ssize_t xe_sriov_packet_write_single(struct xe_device *xe, unsigned int vfid, ret =xe_sriov_pf_migration_restore_produce (xe, vfid, *data);if (ret) {xe_sriov_packet_free (*data); + *data =NULL ; +return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 173/342 spi: sn-f-ospi: Fix resource leak in f_ospi_probe()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Gu <[email protected]>
[ Upstream commit ef3d549e1deb3466c61f3b01d22fc3fe3e5efb08 ]
In f_ospi_probe(), when num_cs validation fails, it returns without calling spi_controller_put() on the SPI controller, which causes a resource leak.
Use devm_spi_alloc_host() instead of spi_alloc_host() to ensure the SPI controller is properly freed when probe fails.
--- drivers/spi/spi-sn-f-ospi.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-)
drivers/spi/spi-sn-f-ospi.c +5 -12
@@ -612,7 +612,7 @@ static int f_ospi_probe(struct platform_device *pdev)u32 num_cs =OSPI_NUM_CS ;int ret; - ctlr =spi_alloc_host (dev,sizeof (*ospi)); + ctlr =devm_spi_alloc_host (dev,sizeof (*ospi));if (!ctlr)return -ENOMEM ;
@@ -636,16 +636,12 @@ static int f_ospi_probe(struct platform_device *pdev)platform_set_drvdata (pdev, ospi); ospi->base =devm_platform_ioremap_resource (pdev,0 ); -if (IS_ERR (ospi->base)) { - ret =PTR_ERR (ospi->base); - goto err_put_ctlr; - } +if (IS_ERR (ospi->base)) +return PTR_ERR (ospi->base); ospi->clk =devm_clk_get_enabled (dev,NULL ); -if (IS_ERR (ospi->clk)) { - ret =PTR_ERR (ospi->clk); - goto err_put_ctlr; - } +if (IS_ERR (ospi->clk)) +return PTR_ERR (ospi->clk);mutex_init (&ospi->mlock);
@@ -662,9 +658,6 @@ static int f_ospi_probe(struct platform_device *pdev) err_destroy_mutex:mutex_destroy (&ospi->mlock); -err_put_ctlr: -spi_controller_put (ctlr); -return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 174/342 ASoC: Intel: catpt: Fix the device initialization
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cezary Rojewski <[email protected]>
[ Upstream commit 5a184f1cb43a8e035251c635f5c47da5dc3e3049 ]
The DMA mask shall be coerced before any buffer allocations for the device are done. At the same time explain why DMA mask of 31 bits is used in the first place.
--- sound/soc/intel/catpt/device.c | 10 +++++++++- sound/soc/intel/catpt/dsp.c | 3 --- 2 files changed, 9 insertions(+), 4 deletions(-)
sound/soc/intel/catpt/device.c +9 -1
@@ -281,7 +281,15 @@ static int catpt_acpi_probe(struct platform_device *pdev)if (IS_ERR (cdev->pci_ba))return PTR_ERR (cdev->pci_ba); -/* alloc buffer for storing DRAM context during dx transitions */ +/* +* As per design HOST is responsible for preserving firmware's runtime +* context during D0 -> D3 -> D0 transitions. Addresses used for DMA +* to/from HOST memory shall be outside the reserved range of 0xFFFxxxxx. +*/ + ret =dma_coerce_mask_and_coherent (cdev->dev,DMA_BIT_MASK (31 )); +if (ret) +return ret; + cdev->dxbuf_vaddr =dmam_alloc_coherent (dev,catpt_dram_size (cdev), &cdev->dxbuf_paddr,GFP_KERNEL );if (!cdev->dxbuf_vaddr)
sound/soc/intel/catpt/dsp.c +0 -3
@@ -125,9 +125,6 @@ int catpt_dmac_probe(struct catpt_dev *cdev) dmac->dev = cdev->dev; dmac->irq = cdev->irq; - ret =dma_coerce_mask_and_coherent (cdev->dev,DMA_BIT_MASK (31 )); -if (ret) -return ret;/* * Caller is responsible for putting device in D0 to allow * for I/O and memory access before probing DW.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 175/342 spi: meson-spicc: Fix double-put in remove path
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Gu <[email protected]>
[ Upstream commit 63542bb402b7013171c9f621c28b609eda4dbf1f ]
meson_spicc_probe() registers the controller with devm_spi_register_controller(), so teardown already drops the controller reference via devm cleanup.
Calling spi_controller_put() again in meson_spicc_remove() causes a double-put.
--- drivers/spi/spi-meson-spicc.c | 2 -- 1 file changed, 2 deletions(-)
drivers/spi/spi-meson-spicc.c +0 -2
@@ -1102,8 +1102,6 @@ static void meson_spicc_remove(struct platform_device *pdev)/* Disable SPI */ writel (0 , spicc->base +SPICC_CONREG ); - -spi_controller_put (spicc->host); }static const struct meson_spicc_data meson_spicc_gx_data = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 176/342 drm/amd/display: Do not skip unrelated mode changes in DSC validation
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yussuf Khalil <[email protected]>
[ Upstream commit aed3d041ab061ec8a64f50a3edda0f4db7280025 ]
Starting with commit 17ce8a6907f7 ("drm/amd/display: Add dsc pre-validation in atomic check"), amdgpu resets the CRTC state mode_changed flag to false when recomputing the DSC configuration results in no timing change for a particular stream.
However, this is incorrect in scenarios where a change in MST/DSC configuration happens in the same KMS commit as another (unrelated) mode change. For example, the integrated panel of a laptop may be configured differently (e.g., HDR enabled/disabled) depending on whether external screens are attached. In this case, plugging in external DP-MST screens may result in the mode_changed flag being dropped incorrectly for the integrated panel if its DSC configuration did not change during precomputation in pre_validate_dsc().
At this point, however, dm_update_crtc_state() has already created new streams for CRTCs with DSC-independent mode changes. In turn, amdgpu_dm_commit_streams() will never release the old stream, resulting in a memory leak. amdgpu_dm_atomic_commit_tail() will never acquire a reference to the new stream either, which manifests as a use-after-free when the stream gets disabled later on:
BUG: KASAN: use-after-free in dc_stream_release+0x25/0x90 [amdgpu] Write of size 4 at addr ffff88813d836524 by task kworker/9:9/29977 Workqueue: events drm_mode_rmfb_work_fn Call Trace: <TASK> dump_stack_lvl+0x6e/0xa0 print_address_description.constprop.0+0x88/0x320 ? dc_stream_release+0x25/0x90 [amdgpu] print_report+0xfc/0x1ff ? srso_alias_return_thunk+0x5/0xfbef5 ? __virt_addr_valid+0x225/0x4e0 ? dc_stream_release+0x25/0x90 [amdgpu] kasan_report+0xe1/0x180 ? dc_stream_release+0x25/0x90 [amdgpu] kasan_check_range+0x125/0x200 dc_stream_release+0x25/0x90 [amdgpu] dc_state_destruct+0x14d/0x5c0 [amdgpu] dc_state_release.part.0+0x4e/0x130 [amdgpu] dm_atomic_destroy_state+0x3f/0x70 [amdgpu] drm_atomic_state_default_clear+0x8ee/0xf30 ? drm_mode_object_put.part.0+0xb1/0x130 __drm_atomic_state_free+0x15c/0x2d0 atomic_remove_fb+0x67e/0x980
Since there is no reliable way of figuring out whether a CRTC has unrelated mode changes pending at the time of DSC validation, remember the value of the mode_changed flag from before the point where a CRTC was marked as potentially affected by a change in DSC configuration. Reset the mode_changed flag to this earlier value instead in pre_validate_dsc().
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 5 +++++ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 1 + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c | 4 +++- 3 files changed, 9 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +5 -0
@@ -12505,6 +12505,11 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, }if (dc_resource_is_dsc_encoding_supported (dc)) { +for_each_oldnew_crtc_in_state (state, crtc, old_crtc_state, new_crtc_state, i) { + dm_new_crtc_state =to_dm_crtc_state (new_crtc_state); + dm_new_crtc_state->mode_changed_independent_from_dsc = new_crtc_state->mode_changed; + } +for_each_oldnew_crtc_in_state (state, crtc, old_crtc_state, new_crtc_state, i) {if (drm_atomic_crtc_needs_modeset (new_crtc_state)) { ret =add_affected_mst_dsc_crtcs (state, crtc);
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +1 -0
@@ -965,6 +965,7 @@ struct dm_crtc_state {bool freesync_vrr_info_changed; +bool mode_changed_independent_from_dsc;bool dsc_force_changed;bool vrr_supported;struct mod_freesync_config freesync_config;
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +3 -1
@@ -1744,9 +1744,11 @@ int pre_validate_dsc(struct drm_atomic_state *state,int ind =find_crtc_index_in_state_by_stream (state, stream);if (ind >=0 ) { +struct dm_crtc_state *dm_new_crtc_state =to_dm_crtc_state (state->crtcs[ind].new_state); +DRM_INFO_ONCE ("%s:%d MST_DSC no mode changed for stream 0x%p\n" , __func__, __LINE__, stream); - state->crtcs[ind].new_state->mode_changed =0 ; + dm_new_crtc_state->base.mode_changed = dm_new_crtc_state->mode_changed_independent_from_dsc; } } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 177/342 ASoC: dt-bindings: stm32: Fix incorrect compatible string in stm32h7-sai match
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jihed Chaibi <[email protected]>
[ Upstream commit 91049ec2e18376ec2192e73ef7be4c7110436350 ]
The conditional block that defines clock constraints for the stm32h7-sai variant references "st,stm32mph7-sai", which does not match any compatible string in the enum. As a result, clock validation for the h7 variant is silently skipped. Correct the compatible string to "st,stm32h7-sai".
--- Documentation/devicetree/bindings/sound/st,stm32-sai.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Documentation/devicetree/bindings/sound/st,stm32-sai.yaml +1 -1
@@ -164,7 +164,7 @@ allOf: properties: compatible: contains: - const: st,stm32mph7-sai + const: st,stm32h7-sai then: properties: clocks:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 178/342 rust: regulator: do not assume that regulator_get() returns non-null
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alice Ryhl <[email protected]>
[ Upstream commit 8121353a4bf8e38afee26299419a78ec108e14a6 ]
The Rust Regulator abstraction uses NonNull to wrap the underlying struct regulator pointer. When CONFIG_REGULATOR is disabled, the C stub for regulator_get returns NULL. from_err_ptr does not treat NULL as an error, so it was passed to NonNull::new_unchecked, causing undefined behavior.
Fix this by using a raw pointer *mut bindings::regulator instead of NonNull. This allows inner to be NULL when CONFIG_REGULATOR is disabled, and leverages the C stubs which are designed to handle NULL or are no-ops.
--- rust/kernel/regulator.rs | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-)
rust/kernel/regulator.rs +18 -15
@@ -23,7 +23,10 @@ use crate::{ prelude::*, }; -use core::{marker::PhantomData , mem::ManuallyDrop , ptr::NonNull }; +use core::{ + marker::PhantomData , + mem::ManuallyDrop ,// +};mod private {pub trait Sealed {}
@@ -232,15 +235,17 @@ pub fn devm_enable_optional(dev: &Device<Bound>, name: &CStr) -> Result {/// /// # Invariants /// -/// - `inner` is a non-null wrapper over a pointer to a `struct -/// regulator` obtained from [`regulator_get()`]. +/// - `inner` is a pointer obtained from a successful call to +/// [`regulator_get()`]. It is treated as an opaque token that may only be +/// accessed using C API methods (e.g., it may be `NULL` if the C API returns +/// `NULL`). /// /// [`regulator_get()`]: https://docs.kernel.org/driver-api/regulator.html#c.regulator_get pub struct Regulator <State >where State :RegulatorState , { - inner:NonNull <bindings::regulator >, + inner: *mut bindings::regulator , _phantom:PhantomData <State >, }
@@ -252,7 +257,7 @@ impl<T: RegulatorState> Regulator<T> {// SAFETY: Safe as per the type invariants of `Regulator`. to_result (unsafe { bindings::regulator_set_voltage ( - self.inner.as_ptr (), + self.inner, min_voltage.as_microvolts (), max_voltage.as_microvolts (), )
@@ -262,7 +267,7 @@ impl<T: RegulatorState> Regulator<T> {/// Gets the current voltage of the regulator. pub fn get_voltage (&self) ->Result <Voltage > {// SAFETY: Safe as per the type invariants of `Regulator`. -let voltage =unsafe { bindings::regulator_get_voltage (self.inner.as_ptr ()) }; +let voltage =unsafe { bindings::regulator_get_voltage (self.inner) };to_result (voltage).map (|()|Voltage ::from_microvolts (voltage)) }
@@ -273,10 +278,8 @@ impl<T: RegulatorState> Regulator<T> {// received from the C code. from_err_ptr (unsafe { bindings::regulator_get (dev.as_raw (), name.as_char_ptr ()) })?; -// SAFETY: We can safely trust `inner` to be a pointer to a valid -// regulator if `ERR_PTR` was not returned. -let inner =unsafe {NonNull ::new_unchecked (inner) }; - +// INVARIANT: `inner` is a pointer obtained from `regulator_get()`, and +// the call was successful. Ok (Self { inner, _phantom:PhantomData ,
@@ -285,12 +288,12 @@ impl<T: RegulatorState> Regulator<T> {fn enable_internal (&self) ->Result {// SAFETY: Safe as per the type invariants of `Regulator`. -to_result (unsafe { bindings::regulator_enable (self.inner.as_ptr ()) }) +to_result (unsafe { bindings::regulator_enable (self.inner) }) }fn disable_internal (&self) ->Result {// SAFETY: Safe as per the type invariants of `Regulator`. -to_result (unsafe { bindings::regulator_disable (self.inner.as_ptr ()) }) +to_result (unsafe { bindings::regulator_disable (self.inner) }) } }
@@ -352,7 +355,7 @@ impl<T: IsEnabled> Regulator<T> {/// Checks if the regulator is enabled. pub fn is_enabled (&self) ->bool {// SAFETY: Safe as per the type invariants of `Regulator`. -unsafe { bindings::regulator_is_enabled (self.inner.as_ptr ()) !=0 } +unsafe { bindings::regulator_is_enabled (self.inner) !=0 } } }
@@ -362,11 +365,11 @@ impl<T: RegulatorState> Drop for Regulator<T> {// SAFETY: By the type invariants, we know that `self` owns a // reference on the enabled refcount, so it is safe to relinquish it // now. -unsafe { bindings::regulator_disable (self.inner.as_ptr ()) }; +unsafe { bindings::regulator_disable (self.inner) }; }// SAFETY: By the type invariants, we know that `self` owns a reference, // so it is safe to relinquish it now. -unsafe { bindings::regulator_put (self.inner.as_ptr ()) }; +unsafe { bindings::regulator_put (self.inner) }; } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 179/342 drm/xe: Implement recent spec updates to Wa_16025250150
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matt Roper <[email protected]>
[ Upstream commit 56781a4597706cd25185b1dedc38841ec6c31496 ]
The hardware teams noticed that the originally documented workaround steps for Wa_16025250150 may not be sufficient to fully avoid a hardware issue. The workaround documentation has been augmented to suggest programming one additional register; make the corresponding change in the driver.
--- drivers/gpu/drm/xe/regs/xe_gt_regs.h | 1 + drivers/gpu/drm/xe/xe_wa.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-)
drivers/gpu/drm/xe/regs/xe_gt_regs.h +1 -0
@@ -544,6 +544,7 @@#define ENABLE_SMP_LD_RENDER_SURFACE_CONTROL REG_BIT(44 - 32)#define FORCE_SLM_FENCE_SCOPE_TO_TILE REG_BIT(42 - 32)#define FORCE_UGM_FENCE_SCOPE_TO_TILE REG_BIT(41 - 32) +#define L3_128B_256B_WRT_DIS REG_BIT(40 - 32)#define MAXREQS_PER_BANK REG_GENMASK(39 - 32, 37 - 32)#define DISABLE_128B_EVICTION_COMMAND_UDW REG_BIT(36 - 32)
drivers/gpu/drm/xe/xe_wa.c +2 -1
@@ -261,7 +261,8 @@ static const struct xe_rtp_entry_sr gt_was[] = { LSN_DIM_Z_WGT_MASK, LSN_LNI_WGT(1) | LSN_LNE_WGT(1) | LSN_DIM_X_WGT(1) | LSN_DIM_Y_WGT(1) | - LSN_DIM_Z_WGT(1))) + LSN_DIM_Z_WGT(1)), + SET(LSC_CHICKEN_BIT_0_UDW, L3_128B_256B_WRT_DIS)) },/* Xe2_HPM */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 180/342 spi: use generic driver_override infrastructure
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Danilo Krummrich <[email protected]>
[ Upstream commit cc34d77dd48708d810c12bfd6f5bf03304f6c824 ]
When a driver is probed through __driver_attach(), the bus' match() callback is called without the device lock held, thus accessing the driver_override field without a lock, which can cause a UAF.
Fix this by using the driver-core driver_override infrastructure taking care of proper locking internally.
Note that calling match() from __driver_attach() without the device lock held is intentional. [1]
Also note that we do not enable the driver_override feature of struct bus_type, as SPI - in contrast to most other buses - passes "" to sysfs_emit() when the driver_override pointer is NULL. Thus, printing "\n" instead of "(null)\n".
--- drivers/spi/spi.c | 19 +++++++------------ include/linux/spi/spi.h | 5 ----- 2 files changed, 7 insertions(+), 17 deletions(-)
drivers/spi/spi.c +7 -12
@@ -50,7 +50,6 @@ static void spidev_release(struct device *dev)struct spi_device *spi =to_spi_device (dev);spi_controller_put (spi->controller); -kfree (spi->driver_override);free_percpu (spi->pcpu_statistics);kfree (spi); }
@@ -73,10 +72,9 @@ static ssize_t driver_override_store(struct device *dev,struct device_attribute *a, const char *buf, size_t count) { - struct spi_device *spi = to_spi_device(dev); int ret; - ret =driver_set_override (dev, &spi->driver_override, buf, count); + ret =__device_set_driver_override (dev, buf, count);if (ret)return ret;
@@ -86,13 +84,8 @@ static ssize_t driver_override_store(struct device *dev,static ssize_t driver_override_show (struct device *dev,struct device_attribute *a,char *buf) { -const struct spi_device *spi =to_spi_device (dev); -ssize_t len; - -device_lock (dev); - len =sysfs_emit (buf,"%s\n" , spi->driver_override ? :"" ); -device_unlock (dev); -return len; +guard (spinlock)(&dev->driver_override.lock); +return sysfs_emit (buf,"%s\n" , dev->driver_override.name ?:"" ); }static DEVICE_ATTR_RW (driver_override);
@@ -376,10 +369,12 @@ static int spi_match_device(struct device *dev, const struct device_driver *drv) {const struct spi_device *spi =to_spi_device (dev);const struct spi_driver *sdrv =to_spi_driver (drv); +int ret;/* Check override first, and if set, only use the named driver */ -if (spi->driver_override) -return strcmp (spi->driver_override, drv->name) ==0 ; + ret =device_match_driver_override (dev, drv); +if (ret >=0 ) +return ret;/* Attempt an OF style match */ if (of_driver_match_device (dev, drv))
include/linux/spi/spi.h +0 -5
@@ -156,10 +156,6 @@ extern void spi_transfer_cs_change_delay_exec(struct spi_message *msg,* @modalias: Name of the driver to use with this device, or an alias * for that name. This appears in the sysfs "modalias" attribute * for driver coldplugging, and in uevents used for hotplugging -* @driver_override: If the name of a driver is written to this attribute, then -* the device will bind to the named driver and only the named driver. -* Do not set directly, because core frees it; use driver_set_override() to -* set or clear it. * @pcpu_statistics: statistics for the spi_device * @word_delay: delay to be inserted between consecutive * words of a transfer
@@ -217,7 +213,6 @@ struct spi_device {void *controller_state;void *controller_data;char modalias[SPI_NAME_SIZE ]; -const char *driver_override;/* The statistics */ struct spi_statistics __percpu *pcpu_statistics;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 181/342 ACPI: EC: clean up handlers on probe failure in acpi_ec_setup()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit f6484cadbcaf26b5844b51bd7307a663dda48ef6 ]
When ec_install_handlers() returns -EPROBE_DEFER on reduced-hardware platforms, it has already started the EC and installed the address space handler with the struct acpi_ec pointer as handler context. However, acpi_ec_setup() propagates the error without any cleanup.
The caller acpi_ec_add() then frees the struct acpi_ec for non-boot instances, leaving a dangling handler context in ACPICA.
Any subsequent AML evaluation that accesses an EC OpRegion field dispatches into acpi_ec_space_handler() with the freed pointer, causing a use-after-free:
BUG: KASAN: slab-use-after-free in mutex_lock (kernel/locking/mutex.c:289) Write of size 8 at addr ffff88800721de38 by task init/1 Call Trace: <TASK> mutex_lock (kernel/locking/mutex.c:289) acpi_ec_space_handler (drivers/acpi/ec.c:1362) acpi_ev_address_space_dispatch (drivers/acpi/acpica/evregion.c:293) acpi_ex_access_region (drivers/acpi/acpica/exfldio.c:246) acpi_ex_field_datum_io (drivers/acpi/acpica/exfldio.c:509) acpi_ex_extract_from_field (drivers/acpi/acpica/exfldio.c:700) acpi_ex_read_data_from_field (drivers/acpi/acpica/exfield.c:327) acpi_ex_resolve_node_to_value (drivers/acpi/acpica/exresolv.c:392) </TASK> Allocated by task 1: acpi_ec_alloc (drivers/acpi/ec.c:1424) acpi_ec_add (drivers/acpi/ec.c:1692) Freed by task 1: kfree (mm/slub.c:6876) acpi_ec_add (drivers/acpi/ec.c:1751)
The bug triggers on reduced-hardware EC platforms (ec->gpe < 0) when the GPIO IRQ provider defers probing. Once the stale handler exists, any unprivileged sysfs read that causes AML to touch an EC OpRegion (battery, thermal, backlight) exercises the dangling pointer.
Fix this by calling ec_remove_handlers() in the error path of acpi_ec_setup() before clearing first_ec. ec_remove_handlers() checks each EC_FLAGS_* bit before acting, so it is safe to call regardless of how far ec_install_handlers() progressed:
-ENODEV (handler not installed): only calls acpi_ec_stop() -EPROBE_DEFER (handler installed): removes handler, stops EC
--- drivers/acpi/ec.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/acpi/ec.c +2 -0
@@ -1655,6 +1655,8 @@ static int acpi_ec_setup(struct acpi_ec *ec, struct acpi_device *device, bool ca ret =ec_install_handlers (ec, device, call_reg);if (ret) { +ec_remove_handlers (ec); +if (ec == first_ec) first_ec =NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 182/342 drm/amdgpu: Fix fence put before wait in amdgpu_amdkfd_submit_ib
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Srinivasan Shanmugam <[email protected]>
[ Upstream commit 7150850146ebfa4ca998f653f264b8df6f7f85be ]
amdgpu_amdkfd_submit_ib() submits a GPU job and gets a fence from amdgpu_ib_schedule(). This fence is used to wait for job completion.
Currently, the code drops the fence reference using dma_fence_put() before calling dma_fence_wait().
If dma_fence_put() releases the last reference, the fence may be freed before dma_fence_wait() is called. This can lead to a use-after-free.
Fix this by waiting on the fence first and releasing the reference only after dma_fence_wait() completes.
Fixes the below:drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c:697 amdgpu_amdkfd_submit_ib() warn: passing freed memory 'f' (line 696)
--- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +2 -2
@@ -687,9 +687,9 @@ int amdgpu_amdkfd_submit_ib(struct amdgpu_device *adev, goto err_ib_sched; } -/* Drop the initial kref_init count (see drm_sched_main as example) */ -dma_fence_put (f); ret =dma_fence_wait (f, false); +/* Drop the returned fence reference after the wait completes */ +dma_fence_put (f); err_ib_sched:amdgpu_job_free (job);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 183/342 hwmon: (adm1177) fix sysfs ABI violation and current unit conversion
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sanman Pradhan <[email protected]>
[ Upstream commit bf08749a6abb6d1959bfdc0edc32c640df407558 ]
The adm1177 driver exposes the current alert threshold through hwmon_curr_max_alarm. This violates the hwmon sysfs ABI, where *_alarm attributes are read-only status flags and writable thresholds must use currN_max.
The driver also stores the threshold internally in microamps, while currN_max is defined in milliamps. Convert the threshold accordingly on both the read and write paths.
Widen the cached threshold and related calculations to 64 bits so that small shunt resistor values do not cause truncation or overflow. Also use 64-bit arithmetic for the mA/uA conversions, clamp writes to the range the hardware can represent, and propagate failures from adm1177_write_alert_thr() instead of silently ignoring them.
Update the hwmon documentation to reflect the attribute rename and the correct units returned by the driver.
--- Documentation/hwmon/adm1177.rst | 8 ++--- drivers/hwmon/adm1177.c | 54 +++++++++++++++++++-------------- 2 files changed, 35 insertions(+), 27 deletions(-)
Documentation/hwmon/adm1177.rst +4 -4
@@ -27,10 +27,10 @@ for details. Sysfs entries ------------- -The following attributes are supported. Current maxim attribute +The following attributes are supported. Current maximum attribute is read-write, all other attributes are read-only. -in0_input Measured voltage in microvolts. +in0_input Measured voltage in millivolts. -curr1_input Measured current in microamperes. -curr1_max_alarm Overcurrent alarm in microamperes. +curr1_input Measured current in milliamperes. +curr1_max Overcurrent shutdown threshold in milliamperes.
drivers/hwmon/adm1177.c +31 -23
111 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 184/342 ASoC: SDCA: fix finding wrong entity
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuming Fan <[email protected]>
[ Upstream commit c673efd5db2223c2e8b885025bcd96bca6cdb171 ]
This patch fixes an issue like:
where searching for the entity 'FU 11' could incorrectly match 'FU 113' first. The driver should first perform an exact match on the full string name. If no exact match is found, it can then fall back to a partial match.
--- sound/soc/sdca/sdca_functions.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
sound/soc/sdca/sdca_functions.c +10 -1
@@ -1568,10 +1568,19 @@ static int find_sdca_entities(struct device *dev, struct sdw_slave *sdw,static struct sdca_entity *find_sdca_entity_by_label (struct sdca_function_data *function,const char *entity_label) { +struct sdca_entity *entity =NULL ;int i;for (i =0 ; i < function->num_entities; i++) { -struct sdca_entity *entity = &function->entities[i]; + entity = &function->entities[i]; + +/* check whole string first*/ +if (!strcmp (entity->label, entity_label)) +return entity; + } + +for (i =0 ; i < function->num_entities; i++) { + entity = &function->entities[i];if (!strncmp (entity->label, entity_label,strlen (entity_label)))return entity;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 185/342 hwmon: (pmbus) Mark lowest/average/highest/rated attributes as read-only
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <[email protected]>
[ Upstream commit 805a5bd1c3f307d45ae4e9cf8915ef16d585a54a ]
Writing those attributes is not supported, so mark them as read-only.
Prior to this change, attempts to write into these attributes returned an error.
Mark boolean fields in struct pmbus_limit_attr and in struct pmbus_sensor_attr as bit fields to reduce configuration data size. The data is scanned only while probing, so performance is not a concern.
--- drivers/hwmon/pmbus/pmbus_core.c | 48 ++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 6 deletions(-)
drivers/hwmon/pmbus/pmbus_core.c +42 -6
@@ -1495,8 +1495,9 @@ static int pmbus_add_label(struct pmbus_data *data,struct pmbus_limit_attr {u16 reg;/* Limit register */ u16 sbit;/* Alarm attribute status bit */ -bool update;/* True if register needs updates */ -bool low;/* True if low limit; for limits with compare functions only */ +bool readonly:1 ;/* True if the attribute is read-only */ +bool update:1 ;/* True if register needs updates */ +bool low:1 ;/* True if low limit; for limits with compare functions only */ const char *attr;/* Attribute name */ const char *alarm;/* Alarm attribute name */ };
@@ -1511,9 +1512,9 @@ struct pmbus_sensor_attr {u8 nlimit;/* # of limit registers */ enum pmbus_sensor_classes class;/* sensor class */ const char *label;/* sensor label */ -bool paged;/* true if paged sensor */ -bool update;/* true if update needed */ -bool compare;/* true if compare function needed */ + bool paged:1; /* true if paged sensor */ + bool update:1; /* true if update needed */ + bool compare:1; /* true if compare function needed */u32 func;/* sensor mask */ u32 sfunc;/* sensor status mask */ int sreg;/* status register */
@@ -1544,7 +1545,7 @@ static int pmbus_add_limit_attrs(struct i2c_client *client, curr =pmbus_add_sensor (data, name, l->attr, index, page,0xff , l->reg, attr->class, attr->update || l->update, - false, true); + l->readonly, true);if (!curr)return -ENOMEM ;if (l->sbit && (info->func[page] & attr->sfunc)) {
@@ -1707,23 +1708,28 @@ static const struct pmbus_limit_attr vin_limit_attrs[] = { }, { .reg = PMBUS_VIRT_READ_VIN_AVG, .update = true, + .readonly = true, .attr = "average", }, { .reg = PMBUS_VIRT_READ_VIN_MIN, .update = true, + .readonly = true, .attr = "lowest", }, { .reg = PMBUS_VIRT_READ_VIN_MAX, .update = true, + .readonly = true, .attr = "highest", }, { .reg = PMBUS_VIRT_RESET_VIN_HISTORY, .attr = "reset_history", }, { .reg = PMBUS_MFR_VIN_MIN, + .readonly = true, .attr = "rated_min", }, { .reg = PMBUS_MFR_VIN_MAX, + .readonly = true, .attr = "rated_max", }, };
@@ -1776,23 +1782,28 @@ static const struct pmbus_limit_attr vout_limit_attrs[] = { }, { .reg = PMBUS_VIRT_READ_VOUT_AVG, .update = true, + .readonly = true, .attr = "average", }, { .reg = PMBUS_VIRT_READ_VOUT_MIN, .update = true, + .readonly = true, .attr = "lowest", }, { .reg = PMBUS_VIRT_READ_VOUT_MAX, .update = true, + .readonly = true, .attr = "highest", }, { .reg = PMBUS_VIRT_RESET_VOUT_HISTORY, .attr = "reset_history", }, { .reg = PMBUS_MFR_VOUT_MIN, + .readonly = true, .attr = "rated_min", }, { .reg = PMBUS_MFR_VOUT_MAX, + .readonly = true, .attr = "rated_max", }, };
@@ -1852,20 +1863,24 @@ static const struct pmbus_limit_attr iin_limit_attrs[] = { }, { .reg = PMBUS_VIRT_READ_IIN_AVG, .update = true, + .readonly = true, .attr = "average", }, { .reg = PMBUS_VIRT_READ_IIN_MIN, .update = true, + .readonly = true, .attr = "lowest", }, { .reg = PMBUS_VIRT_READ_IIN_MAX, .update = true, + .readonly = true, .attr = "highest", }, { .reg = PMBUS_VIRT_RESET_IIN_HISTORY, .attr = "reset_history", }, { .reg = PMBUS_MFR_IIN_MAX, + .readonly = true, .attr = "rated_max", }, };
@@ -1889,20 +1904,24 @@ static const struct pmbus_limit_attr iout_limit_attrs[] = { }, { .reg = PMBUS_VIRT_READ_IOUT_AVG, .update = true, + .readonly = true, .attr = "average", }, { .reg = PMBUS_VIRT_READ_IOUT_MIN, .update = true, + .readonly = true, .attr = "lowest", }, { .reg = PMBUS_VIRT_READ_IOUT_MAX, .update = true, + .readonly = true, .attr = "highest", }, { .reg = PMBUS_VIRT_RESET_IOUT_HISTORY, .attr = "reset_history", }, { .reg = PMBUS_MFR_IOUT_MAX, + .readonly = true, .attr = "rated_max", }, };
@@ -1943,20 +1962,24 @@ static const struct pmbus_limit_attr pin_limit_attrs[] = { }, { .reg = PMBUS_VIRT_READ_PIN_AVG, .update = true, + .readonly = true, .attr = "average", }, { .reg = PMBUS_VIRT_READ_PIN_MIN, .update = true, + .readonly = true, .attr = "input_lowest", }, { .reg = PMBUS_VIRT_READ_PIN_MAX, .update = true, + .readonly = true, .attr = "input_highest", }, { .reg = PMBUS_VIRT_RESET_PIN_HISTORY, .attr = "reset_history", }, { .reg = PMBUS_MFR_PIN_MAX, + .readonly = true, .attr = "rated_max", }, };
@@ -1980,20 +2003,24 @@ static const struct pmbus_limit_attr pout_limit_attrs[] = { }, { .reg = PMBUS_VIRT_READ_POUT_AVG, .update = true, + .readonly = true, .attr = "average", }, { .reg = PMBUS_VIRT_READ_POUT_MIN, .update = true, + .readonly = true, .attr = "input_lowest", }, { .reg = PMBUS_VIRT_READ_POUT_MAX, .update = true, + .readonly = true, .attr = "input_highest", }, { .reg = PMBUS_VIRT_RESET_POUT_HISTORY, .attr = "reset_history", }, { .reg = PMBUS_MFR_POUT_MAX, + .readonly = true, .attr = "rated_max", }, };
@@ -2049,18 +2076,22 @@ static const struct pmbus_limit_attr temp_limit_attrs[] = { .sbit = PB_TEMP_OT_FAULT, }, { .reg = PMBUS_VIRT_READ_TEMP_MIN, + .readonly = true, .attr = "lowest", }, { .reg = PMBUS_VIRT_READ_TEMP_AVG, + .readonly = true, .attr = "average", }, { .reg = PMBUS_VIRT_READ_TEMP_MAX, + .readonly = true, .attr = "highest", }, { .reg = PMBUS_VIRT_RESET_TEMP_HISTORY, .attr = "reset_history", }, { .reg = PMBUS_MFR_MAX_TEMP_1, + .readonly = true, .attr = "rated_max", }, };
@@ -2090,18 +2121,22 @@ static const struct pmbus_limit_attr temp_limit_attrs2[] = { .sbit = PB_TEMP_OT_FAULT, }, { .reg = PMBUS_VIRT_READ_TEMP2_MIN, + .readonly = true, .attr = "lowest", }, { .reg = PMBUS_VIRT_READ_TEMP2_AVG, + .readonly = true, .attr = "average", }, { .reg = PMBUS_VIRT_READ_TEMP2_MAX, + .readonly = true, .attr = "highest", }, { .reg = PMBUS_VIRT_RESET_TEMP2_HISTORY, .attr = "reset_history", }, { .reg = PMBUS_MFR_MAX_TEMP_2, + .readonly = true, .attr = "rated_max", }, };
@@ -2131,6 +2166,7 @@ static const struct pmbus_limit_attr temp_limit_attrs3[] = { .sbit = PB_TEMP_OT_FAULT, }, { .reg = PMBUS_MFR_MAX_TEMP_3, + .readonly = true, .attr = "rated_max", }, };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 186/342 hwmon: (pmbus) Introduce the concept of "write-only" attributes
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <[email protected]>
[ Upstream commit cd658475e7694d58e1c40dabc1dacf8431ccedb2 ]
Attributes intended to clear sensor history are intended to be writeable only. Reading those attributes today results in reporting more or less random values. To avoid ABI surprises, have those attributes explicitly return 0 when reading.
--- drivers/hwmon/pmbus/pmbus_core.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-)
drivers/hwmon/pmbus/pmbus_core.c +24 -8
@@ -1209,6 +1209,12 @@ static ssize_t pmbus_show_boolean(struct device *dev,return sysfs_emit (buf,"%d\n" , val); } +static ssize_t pmbus_show_zero (struct device *dev, +struct device_attribute *devattr,char *buf) +{ +return sysfs_emit (buf,"0\n" ); +} +static ssize_t pmbus_show_sensor (struct device *dev,struct device_attribute *devattr,char *buf) {
@@ -1407,7 +1413,7 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,int reg, enum pmbus_sensor_classes class, bool update, bool readonly, - bool convert) + bool writeonly, bool convert) { struct pmbus_sensor *sensor;struct device_attribute *a;
@@ -1436,7 +1442,8 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data, sensor->data = -ENODATA ;pmbus_dev_attr_init (a, sensor->name, readonly ?0444 :0644 , - pmbus_show_sensor, pmbus_set_sensor); + writeonly ? pmbus_show_zero : pmbus_show_sensor, + pmbus_set_sensor);if (pmbus_add_attribute (data, &a->attr))return NULL ;
@@ -1496,6 +1503,7 @@ struct pmbus_limit_attr {u16 reg;/* Limit register */ u16 sbit;/* Alarm attribute status bit */ bool readonly:1; /* True if the attribute is read-only */ + bool writeonly:1; /* True if the attribute is write-only */ bool update:1; /* True if register needs updates */ bool low:1; /* True if low limit; for limits with compare functions only */const char *attr;/* Attribute name */
@@ -1545,7 +1553,7 @@ static int pmbus_add_limit_attrs(struct i2c_client *client, curr =pmbus_add_sensor (data, name, l->attr, index, page,0xff , l->reg, attr->class, attr->update || l->update, - l->readonly, true); + l->readonly, l->writeonly, true);if (!curr)return -ENOMEM ;if (l->sbit && (info->func[page] & attr->sfunc)) {
@@ -1585,7 +1593,7 @@ static int pmbus_add_sensor_attrs_one(struct i2c_client *client,return ret; } base =pmbus_add_sensor (data, name,"input" , index, page, phase, - attr->reg, attr->class, true, true, true); + attr->reg, attr->class, true, true, false, true);if (!base)return -ENOMEM ;/* No limit and alarm attributes for phase specific sensors */
@@ -1722,6 +1730,7 @@ static const struct pmbus_limit_attr vin_limit_attrs[] = { .attr = "highest", }, { .reg = PMBUS_VIRT_RESET_VIN_HISTORY, + .writeonly = true, .attr = "reset_history", }, { .reg = PMBUS_MFR_VIN_MIN,
@@ -1796,6 +1805,7 @@ static const struct pmbus_limit_attr vout_limit_attrs[] = { .attr = "highest", }, { .reg = PMBUS_VIRT_RESET_VOUT_HISTORY, + .writeonly = true, .attr = "reset_history", }, { .reg = PMBUS_MFR_VOUT_MIN,
@@ -1877,6 +1887,7 @@ static const struct pmbus_limit_attr iin_limit_attrs[] = { .attr = "highest", }, { .reg = PMBUS_VIRT_RESET_IIN_HISTORY, + .writeonly = true, .attr = "reset_history", }, { .reg = PMBUS_MFR_IIN_MAX,
@@ -1918,6 +1929,7 @@ static const struct pmbus_limit_attr iout_limit_attrs[] = { .attr = "highest", }, { .reg = PMBUS_VIRT_RESET_IOUT_HISTORY, + .writeonly = true, .attr = "reset_history", }, { .reg = PMBUS_MFR_IOUT_MAX,
@@ -1976,6 +1988,7 @@ static const struct pmbus_limit_attr pin_limit_attrs[] = { .attr = "input_highest", }, { .reg = PMBUS_VIRT_RESET_PIN_HISTORY, + .writeonly = true, .attr = "reset_history", }, { .reg = PMBUS_MFR_PIN_MAX,
@@ -2017,6 +2030,7 @@ static const struct pmbus_limit_attr pout_limit_attrs[] = { .attr = "input_highest", }, { .reg = PMBUS_VIRT_RESET_POUT_HISTORY, + .writeonly = true, .attr = "reset_history", }, { .reg = PMBUS_MFR_POUT_MAX,
@@ -2088,6 +2102,7 @@ static const struct pmbus_limit_attr temp_limit_attrs[] = { .attr = "highest", }, { .reg = PMBUS_VIRT_RESET_TEMP_HISTORY, + .writeonly = true, .attr = "reset_history", }, { .reg = PMBUS_MFR_MAX_TEMP_1,
@@ -2133,6 +2148,7 @@ static const struct pmbus_limit_attr temp_limit_attrs2[] = { .attr = "highest", }, { .reg = PMBUS_VIRT_RESET_TEMP2_HISTORY, + .writeonly = true, .attr = "reset_history", }, { .reg = PMBUS_MFR_MAX_TEMP_2,
@@ -2250,7 +2266,7 @@ static int pmbus_add_fan_ctrl(struct i2c_client *client, sensor =pmbus_add_sensor (data,"fan" ,"target" , index, page,0xff ,PMBUS_VIRT_FAN_TARGET_1 + id,PSC_FAN , - false, false, true); + false, false, false, true);if (!sensor)return -ENOMEM ;
@@ -2261,14 +2277,14 @@ static int pmbus_add_fan_ctrl(struct i2c_client *client, sensor =pmbus_add_sensor (data,"pwm" ,NULL , index, page,0xff ,PMBUS_VIRT_PWM_1 + id,PSC_PWM , - false, false, true); + false, false, false, true);if (!sensor)return -ENOMEM ; sensor =pmbus_add_sensor (data,"pwm" ,"enable" , index, page,0xff ,PMBUS_VIRT_PWM_ENABLE_1 + id,PSC_PWM , - true, false, false); + true, false, false, false);if (!sensor)return -ENOMEM ;
@@ -2310,7 +2326,7 @@ static int pmbus_add_fan_attributes(struct i2c_client *client,if (pmbus_add_sensor (data,"fan" ,"input" , index, page,0xff , pmbus_fan_registers[f], -PSC_FAN , true, true, true) ==NULL ) +PSC_FAN , true, true, false, true) ==NULL )return -ENOMEM ;/* Fan control */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 187/342 hwmon: (pmbus/core) Protect regulator operations with mutex
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <[email protected]>
[ Upstream commit 754bd2b4a084b90b5e7b630e1f423061a9b9b761 ]
The regulator operations pmbus_regulator_get_voltage(), pmbus_regulator_set_voltage(), and pmbus_regulator_list_voltage() access PMBus registers and shared data but were not protected by the update_lock mutex. This could lead to race conditions.
However, adding mutex protection directly to these functions causes a deadlock because pmbus_regulator_notify() (which calls regulator_notifier_call_chain()) is often called with the mutex already held (e.g., from pmbus_fault_handler()). If a regulator callback then calls one of the now-protected voltage functions, it will attempt to acquire the same mutex.
Rework pmbus_regulator_notify() to utilize a worker function to send notifications outside of the mutex protection. Events are stored as atomics in a per-page bitmask and processed by the worker.
Initialize the worker and its associated data during regulator registration, and ensure it is cancelled on device removal using devm_add_action_or_reset().
While at it, remove the unnecessary include of linux/of.h.
--- drivers/hwmon/pmbus/pmbus_core.c | 114 ++++++++++++++++++++++++------- 1 file changed, 89 insertions(+), 25 deletions(-)
drivers/hwmon/pmbus/pmbus_core.c +89 -25
@@ -6,6 +6,7 @@* Copyright (c) 2012 Guenter Roeck */ +#include <linux/atomic.h> #include <linux/debugfs.h> #include <linux/delay.h> #include <linux/dcache.h>
@@ -21,8 +22,8 @@#include <linux/pmbus.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> -#include <linux/of.h> #include <linux/thermal.h> +#include <linux/workqueue.h> #include "pmbus.h" /*
@@ -112,6 +113,11 @@ struct pmbus_data {struct mutex update_lock; +#if IS_ENABLED (CONFIG_REGULATOR ) +atomic_t regulator_events[PMBUS_PAGES ]; +struct work_struct regulator_notify_work; +#endif +bool has_status_word;/* device uses STATUS_WORD register */ int (*read_status)(struct i2c_client *client,int page);
@@ -3228,12 +3234,19 @@ static int pmbus_regulator_get_voltage(struct regulator_dev *rdev) .class = PSC_VOLTAGE_OUT, .convert = true, }; +int ret; +mutex_lock (&data->update_lock); s.data =_pmbus_read_word_data (client, s.page,0xff ,PMBUS_READ_VOUT ); -if (s.data <0 ) -return s.data; +if (s.data <0 ) { + ret = s.data; + goto unlock; + } -return (int )pmbus_reg2data (data, &s) *1000 ;/* unit is uV */ + ret = (int )pmbus_reg2data (data, &s) *1000 ;/* unit is uV */ +unlock: +mutex_unlock (&data->update_lock); +return ret; } static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv,
@@ -3250,16 +3263,22 @@ static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv, };int val =DIV_ROUND_CLOSEST (min_uv,1000 );/* convert to mV */ int low, high; +int ret; *selector =0 ; +mutex_lock (&data->update_lock); low =pmbus_regulator_get_low_margin (client, s.page); -if (low <0 ) -return low; +if (low <0 ) { + ret = low; + goto unlock; + } high =pmbus_regulator_get_high_margin (client, s.page); -if (high <0 ) -return high; +if (high <0 ) { + ret = high; + goto unlock; + }/* Make sure we are within margins */ if (low > val)
@@ -3269,7 +3288,10 @@ static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv, val =pmbus_data2reg (data, &s, val); -return _pmbus_write_word_data (client, s.page,PMBUS_VOUT_COMMAND , (u16 )val); + ret =_pmbus_write_word_data (client, s.page,PMBUS_VOUT_COMMAND , (u16 )val); +unlock: +mutex_unlock (&data->update_lock); +return ret; } static int pmbus_regulator_list_voltage(struct regulator_dev *rdev,
@@ -3279,6 +3301,7 @@ static int pmbus_regulator_list_voltage(struct regulator_dev *rdev,struct i2c_client *client =to_i2c_client (dev->parent);struct pmbus_data *data =i2c_get_clientdata (client);int val, low, high; +int ret;if (data->flags &PMBUS_VOUT_PROTECTED )return 0 ;
@@ -3291,18 +3314,29 @@ static int pmbus_regulator_list_voltage(struct regulator_dev *rdev, val =DIV_ROUND_CLOSEST (rdev->desc->min_uV + (rdev->desc->uV_step * selector),1000 );/* convert to mV */ +mutex_lock (&data->update_lock); + low =pmbus_regulator_get_low_margin (client,rdev_get_id (rdev)); -if (low <0 ) -return low; +if (low <0 ) { + ret = low; + goto unlock; + } high =pmbus_regulator_get_high_margin (client,rdev_get_id (rdev)); -if (high <0 ) -return high; +if (high <0 ) { + ret = high; + goto unlock; + } -if (val >= low && val <= high) -return val *1000 ;/* unit is uV */ +if (val >= low && val <= high) { + ret = val *1000 ;/* unit is uV */ + goto unlock; + } -return 0 ; + ret =0 ; +unlock: +mutex_unlock (&data->update_lock); +return ret; }const struct regulator_ops pmbus_regulator_ops = {
@@ -3333,12 +3367,42 @@ int pmbus_regulator_init_cb(struct regulator_dev *rdev, }EXPORT_SYMBOL_NS_GPL (pmbus_regulator_init_cb,"PMBUS" ); +static void pmbus_regulator_notify_work_cancel (void *data) +{ +struct pmbus_data *pdata = data; + +cancel_work_sync (&pdata->regulator_notify_work); +} + +static void pmbus_regulator_notify_worker (struct work_struct *work) +{ +struct pmbus_data *data = + container_of(work, struct pmbus_data, regulator_notify_work); +int i, j; + +for (i =0 ; i < data->info->pages; i++) { +int event; + + event =atomic_xchg (&data->regulator_events[i],0 ); +if (!event) +continue ; + +for (j =0 ; j < data->info->num_regulators; j++) { +if (i ==rdev_get_id (data->rdevs[j])) { +regulator_notifier_call_chain (data->rdevs[j], + event,NULL ); +break ; + } + } + } +} +static int pmbus_regulator_register (struct pmbus_data *data) {struct device *dev = data->dev;const struct pmbus_driver_info *info = data->info;const struct pmbus_platform_data *pdata =dev_get_platdata (dev); -int i; +int i, ret; data->rdevs =devm_kzalloc (dev,sizeof (struct regulator_dev *) * info->num_regulators,GFP_KERNEL );
@@ -3362,19 +3426,19 @@ static int pmbus_regulator_register(struct pmbus_data *data) info->reg_desc[i].name); } +INIT_WORK (&data->regulator_notify_work, pmbus_regulator_notify_worker); + + ret =devm_add_action_or_reset (dev, pmbus_regulator_notify_work_cancel, data); +if (ret) +return ret; +return 0 ; }static void pmbus_regulator_notify (struct pmbus_data *data,int page,int event) { -int j; - -for (j =0 ; j < data->info->num_regulators; j++) { -if (page ==rdev_get_id (data->rdevs[j])) { -regulator_notifier_call_chain (data->rdevs[j], event,NULL ); -break ; - } - } +atomic_or (event, &data->regulator_events[page]); +schedule_work (&data->regulator_notify_work); }#else static int pmbus_regulator_register (struct pmbus_data *data)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 188/342 sysctl: fix uninitialized variable in proc_do_large_bitmap
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marc Buerg <[email protected]>
[ Upstream commit f63a9df7e3f9f842945d292a19d9938924f066f9 ]
proc_do_large_bitmap() does not initialize variable c, which is expected to be set to a trailing character by proc_get_long().
However, proc_get_long() only sets c when the input buffer contains a trailing character after the parsed value.
If c is not initialized it may happen to contain a '-'. If this is the case proc_do_large_bitmap() expects to be able to parse a second part of the input buffer. If there is no second part an unjustified -EINVAL will be returned.
Initialize c to 0 to prevent returning -EINVAL on valid input.
--- kernel/sysctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/sysctl.c +1 -1
@@ -895,7 +895,7 @@ int proc_do_large_bitmap(const struct ctl_table *table, int dir,unsigned long bitmap_len = table->maxlen;unsigned long *bitmap = *(unsigned long **) table->data;unsigned long *tmp_bitmap =NULL ; -char tr_a[] = {'-' ,',' ,'\n' }, tr_b[] = {',' ,'\n' ,0 }, c; +char tr_a[] = {'-' ,',' ,'\n' }, tr_b[] = {',' ,'\n' ,0 }, c =0 ;if (!bitmap || !bitmap_len || !left || (*ppos &&SYSCTL_KERN_TO_USER (dir))) { *lenp =0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 189/342 ASoC: adau1372: Fix unchecked clk_prepare_enable() return value
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jihed Chaibi <[email protected]>
[ Upstream commit 326fe8104a4020d30080d37ac8b6b43893cdebca ]
adau1372_set_power() calls clk_prepare_enable() but discards the return value. If the clock enable fails, the driver proceeds to access registers on unpowered hardware, potentially causing silent corruption.
Make adau1372_set_power() return int and propagate the error from clk_prepare_enable(). Update adau1372_set_bias_level() to return the error directly for the STANDBY and OFF cases.
--- sound/soc/codecs/adau1372.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-)
sound/soc/codecs/adau1372.c +10 -7
@@ -782,15 +782,18 @@ static void adau1372_enable_pll(struct adau1372 *adau1372)dev_err (adau1372->dev,"Failed to lock PLL\n" ); } -static void adau1372_set_power (struct adau1372 *adau1372,bool enable) +static int adau1372_set_power (struct adau1372 *adau1372,bool enable) {if (adau1372->enabled == enable) -return ; +return 0 ;if (enable) {unsigned int clk_ctrl =ADAU1372_CLK_CTRL_MCLK_EN ; +int ret; -clk_prepare_enable (adau1372->mclk); + ret =clk_prepare_enable (adau1372->mclk); +if (ret) +return ret;if (adau1372->pd_gpio)gpiod_set_value (adau1372->pd_gpio,0 );
@@ -829,6 +832,8 @@ static void adau1372_set_power(struct adau1372 *adau1372, bool enable) } adau1372->enabled = enable; + +return 0 ; } static int adau1372_set_bias_level(struct snd_soc_component *component,
@@ -842,11 +847,9 @@ static int adau1372_set_bias_level(struct snd_soc_component *component,case SND_SOC_BIAS_PREPARE :break ;case SND_SOC_BIAS_STANDBY : -adau1372_set_power (adau1372, true); -break ; +return adau1372_set_power (adau1372, true);case SND_SOC_BIAS_OFF : -adau1372_set_power (adau1372, false); -break ; +return adau1372_set_power (adau1372, false); }return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 190/342 ASoC: adau1372: Fix clock leak on PLL lock failure
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jihed Chaibi <[email protected]>
[ Upstream commit bfe6a264effcb6fe99ad7ceaf9e8c7439fc9555b ]
adau1372_enable_pll() was a void function that logged a dev_err() on PLL lock timeout but did not propagate the error. As a result, adau1372_set_power() would continue with adau1372->enabled set to true despite the PLL being unlocked, and the mclk left enabled with no corresponding disable on the error path.
Convert adau1372_enable_pll() to return int, using -ETIMEDOUT on lock timeout and propagating regmap errors directly. In adau1372_set_power(), check the return value and unwind in reverse order: restore regcache to cache-only mode, reassert GPIO power-down, and disable the clock before returning the error.
--- sound/soc/codecs/adau1372.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-)
sound/soc/codecs/adau1372.c +14 -3
@@ -762,7 +762,7 @@ static int adau1372_startup(struct snd_pcm_substream *substream, struct snd_soc_return 0 ; } -static void adau1372_enable_pll (struct adau1372 *adau1372) +static int adau1372_enable_pll (struct adau1372 *adau1372) {unsigned int val, timeout =0 ;int ret;
@@ -778,8 +778,12 @@ static void adau1372_enable_pll(struct adau1372 *adau1372) timeout++; }while (!(val &1 ) && timeout <3 ); -if (ret <0 || !(val &1 )) +if (ret <0 || !(val &1 )) {dev_err (adau1372->dev,"Failed to lock PLL\n" ); +return ret <0 ? ret : -ETIMEDOUT ; + } + +return 0 ; }static int adau1372_set_power (struct adau1372 *adau1372,bool enable)
@@ -807,7 +811,14 @@ static int adau1372_set_power(struct adau1372 *adau1372, bool enable)* accessed. */ if (adau1372->use_pll) { -adau1372_enable_pll (adau1372); + ret =adau1372_enable_pll (adau1372); +if (ret) { +regcache_cache_only (adau1372->regmap, true); +if (adau1372->pd_gpio) +gpiod_set_value (adau1372->pd_gpio,1 ); +clk_disable_unprepare (adau1372->mclk); +return ret; + } clk_ctrl |=ADAU1372_CLK_CTRL_CLKSRC ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 191/342 spi: spi-fsl-lpspi: fix teardown order issue (UAF)
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marc Kleine-Budde <[email protected]>
[ Upstream commit b341c1176f2e001b3adf0b47154fc31589f7410e ]
There is a teardown order issue in the driver. The SPI controller is registered using devm_spi_register_controller(), which delays unregistration of the SPI controller until after the fsl_lpspi_remove() function returns.
As the fsl_lpspi_remove() function synchronously tears down the DMA channels, a running SPI transfer triggers the following NULL pointer dereference due to use after free:
| fsl_lpspi 42550000.spi: I/O Error in DMA RX
| Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000 [...]
| Call trace: | fsl_lpspi_dma_transfer+0x260/0x340 [spi_fsl_lpspi] | fsl_lpspi_transfer_one+0x198/0x448 [spi_fsl_lpspi] | spi_transfer_one_message+0x49c/0x7c8 | __spi_pump_transfer_message+0x120/0x420 | __spi_sync+0x2c4/0x520 | spi_sync+0x34/0x60 | spidev_message+0x20c/0x378 [spidev] | spidev_ioctl+0x398/0x750 [spidev]
[...]
Switch from devm_spi_register_controller() to spi_register_controller() in fsl_lpspi_probe() and add the corresponding spi_unregister_controller() in fsl_lpspi_remove().
--- drivers/spi/spi-fsl-lpspi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/spi/spi-fsl-lpspi.c +2 -1
@@ -972,7 +972,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev)enable_irq (irq); } - ret =devm_spi_register_controller (&pdev->dev, controller); + ret =spi_register_controller (controller);if (ret <0 ) {dev_err_probe (&pdev->dev, ret,"spi_register_controller error\n" ); goto free_dma;
@@ -998,6 +998,7 @@ static void fsl_lpspi_remove(struct platform_device *pdev)struct fsl_lpspi_data *fsl_lpspi =spi_controller_get_devdata (controller); +spi_unregister_controller (controller);fsl_lpspi_dma_exit (controller);pm_runtime_dont_use_autosuspend (fsl_lpspi->dev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 192/342 io_uring/fdinfo: fix SQE_MIXED SQE displaying
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jens Axboe <[email protected]>
[ Upstream commit b59efde9e6c122207c16169d3d0deb623956eae9 ]
When displaying pending SQEs for a MIXED ring, each 128-byte SQE increments sq_head to skip the second slot, but the loop counter is not adjusted. This can cause the loop to read past sq_tail by one entry for each 128-byte SQE encountered, displaying SQEs that haven't been made consumable yet by the application.
Match the kernel's own consumption logic in io_init_req() which decrements what's left when consuming the extra slot.
--- io_uring/fdinfo.c | 1 + 1 file changed, 1 insertion(+)
io_uring/fdinfo.c +1 -0
@@ -125,6 +125,7 @@ static void __io_uring_show_fdinfo(struct io_ring_ctx *ctx, struct seq_file *m) sq_idx);break ; } + i++; sqe128 = true; } seq_printf(m, "%5u: opcode:%s, fd:%d, flags:%x, off:%llu, "
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 193/342 io_uring/fdinfo: fix OOB read in SQE_MIXED wrap check
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicholas Carlini <[email protected]>
[ Upstream commit 5170efd9c344c68a8075dcb8ed38d3f8a60e7ed4 ]
__io_uring_show_fdinfo() iterates over pending SQEs and, for 128-byte SQEs on an IORING_SETUP_SQE_MIXED ring, needs to detect when the second half of the SQE would be past the end of the sq_sqes array. The current check tests (++sq_head & sq_mask) == 0, but sq_head is only incremented when a 128-byte SQE is encountered, not on every iteration. The actual array index is sq_idx = (i + sq_head) & sq_mask, which can be sq_mask (the last slot) while the wrap check passes.
Fix by checking sq_idx directly. Keep the sq_head increment so the loop still skips the second half of the 128-byte SQE on the next iteration.
--- io_uring/fdinfo.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
io_uring/fdinfo.c +2 -1
@@ -119,12 +119,13 @@ static void __io_uring_show_fdinfo(struct io_ring_ctx *ctx, struct seq_file *m) sq_idx);break ; } -if ((++sq_head & sq_mask) ==0 ) { +if (sq_idx == sq_mask) {seq_printf (m,"%5u: corrupted sqe, wrapping 128B entry\n" , sq_idx);break ; } + sq_head++; i++; sqe128 = true; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 194/342 ALSA: usb-audio: Exclude Scarlett 2i4 1st Gen from SKIP_IFACE_SETUP
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Geoffrey D. Bennett <[email protected]>
[ Upstream commit 990a8b0732cf899d4a0f847b0a67efeb9a384c82 ]
Same issue that the Scarlett 2i2 1st Gen had:QUIRK_FLAG_SKIP_IFACE_SETUP causes distorted/flanging audio on the Scarlett 2i4 1st Gen (1235:800a).
--- sound/usb/quirks.c | 1 + 1 file changed, 1 insertion(+)
sound/usb/quirks.c +1 -0
@@ -2426,6 +2426,7 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {VENDOR_FLG (0x07fd ,/* MOTU */ QUIRK_FLAG_VALIDATE_RATES ),DEVICE_FLG (0x1235 ,0x8006 ,0 ),/* Focusrite Scarlett 2i2 1st Gen */ +DEVICE_FLG (0x1235 ,0x800a ,0 ),/* Focusrite Scarlett 2i4 1st Gen */ VENDOR_FLG (0x1235 ,/* Focusrite Novation */ QUIRK_FLAG_SKIP_IFACE_SETUP ), VENDOR_FLG(0x1511, /* AURALiC */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 195/342 s390/syscalls: Add spectre boundary for syscall dispatch table
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Greg Kroah-Hartman <[email protected]>
commit 48b8814e25d073dd84daf990a879a820bad2bcbd upstream.
The s390 syscall number is directly controlled by userspace, but does not have an array_index_nospec() boundary to prevent access past the syscall function pointer tables.
--- arch/s390/kernel/syscall.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
arch/s390/kernel/syscall.c +4 -1
@@ -13,6 +13,7 @@*/ #include <linux/cpufeature.h> +#include <linux/nospec.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/mm.h>
@@ -131,8 +132,10 @@ void noinstr __do_syscall(struct pt_regsif (unlikely (test_and_clear_pt_regs_flag (regs,PIF_SYSCALL_RET_SET ))) goto out; regs->gprs[2 ] = -ENOSYS ; -if (likely (nr < NR_syscalls)) +if (likely (nr < NR_syscalls)) { + nr =array_index_nospec (nr, NR_syscalls); regs->gprs[2 ] = sys_call_table[nr](regs); + } out:syscall_exit_to_user_mode (regs); }
Greg Kroah-Hartman
maintainerPATCH 196/342 s390/barrier: Make array_index_mask_nospec() __always_inline
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vasily Gorbik <[email protected]>
commit c5c0a268b38adffbb2e70e6957017537ff54c157 upstream.
Mark array_index_mask_nospec() as __always_inline to guarantee the mitigation is emitted inline regardless of compiler inlining decisions.
--- arch/s390/include/asm/barrier.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/s390/include/asm/barrier.h +2 -2
@@ -62,8 +62,8 @@ do { \* @size: number of elements in array */ #define array_index_mask_nospec array_index_mask_nospec -static inline unsigned long array_index_mask_nospec (unsigned long index, -unsigned long size) +static __always_inline unsigned long array_index_mask_nospec (unsigned long index, +unsigned long size) {unsigned long mask;
Greg Kroah-Hartman
maintainerPATCH 197/342 s390/entry: Scrub r12 register on kernel entry
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vasily Gorbik <[email protected]>
commit 0738d395aab8fae3b5a3ad3fc640630c91693c27 upstream.
Before commit f33f2d4c7c80 ("s390/bp: remove TIF_ISOLATE_BP"), all entry handlers loaded r12 with the current task pointer (lg %r12,__LC_CURRENT) for use by the BPENTER/BPEXIT macros. That commit removed TIF_ISOLATE_BP, dropping both the branch prediction macros and the r12 load, but did not add r12 to the register clearing sequence.
Add the missing xgr %r12,%r12 to make the register scrub consistent across all entry points.
--- arch/s390/kernel/entry.S | 3 +++ 1 file changed, 3 insertions(+)
arch/s390/kernel/entry.S +3 -0
@@ -260,6 +260,7 @@ SYM_CODE_START(system_call) xgr %r9,%r9 xgr %r10,%r10 xgr %r11,%r11 + xgr %r12,%r12 la %r2,STACK_FRAME_OVERHEAD(%r15) # pointer to pt_regs mvc __PT_R8(64,%r2),__LC_SAVE_AREA(%r13) MBEAR %r2,%r13
@@ -396,6 +397,7 @@ SYM_CODE_START(\name) xgr %r6,%r6 xgr %r7,%r7 xgr %r10,%r10 + xgr %r12,%r12 xc __PT_FLAGS(8,%r11),__PT_FLAGS(%r11) mvc __PT_R8(64,%r11),__LC_SAVE_AREA(%r13) MBEAR %r11,%r13
@@ -485,6 +487,7 @@ SYM_CODE_START(mcck_int_handler) xgr %r6,%r6 xgr %r7,%r7 xgr %r10,%r10 + xgr %r12,%r12 stmg %r8,%r9,__PT_PSW(%r11) xc __PT_FLAGS(8,%r11),__PT_FLAGS(%r11) xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
Greg Kroah-Hartman
maintainerPATCH 198/342 tracing: Drain deferred trigger frees if kthread creation fails
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wesley Atwell <[email protected]>
commit 250ab25391edeeab8462b68be42e4904506c409c upstream.
Boot-time trigger registration can fail before the trigger-data cleanup kthread exists. Deferring those frees until late init is fine, but the post-boot fallback must still drain the deferred list if kthread creation never succeeds.
Otherwise, boot-deferred nodes can accumulate on trigger_data_free_list, later frees fall back to synchronously freeing only the current object, and the older queued entries are leaked forever.
To trigger this, add the following to the kernel command line:
trace_event=sched_switch trace_trigger=sched_switch.traceon,sched_switch.traceon
The second traceon trigger will fail and be freed. This triggers a NULL pointer dereference and crashes the kernel.
Keep the deferred boot-time behavior, but when kthread creation fails, drain the whole queued list synchronously. Do the same in the late-init drain path so queued entries are not stranded there either.
--- kernel/trace/trace_events_trigger.c | 79 ++++++++++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 13 deletions(-)
kernel/trace/trace_events_trigger.c +66 -13
@@ -22,6 +22,39 @@ static struct task_struct *trigger_kthrestatic struct llist_head trigger_data_free_list;static DEFINE_MUTEX (trigger_data_kthread_mutex); +static int trigger_kthread_fn (void *ignore); + +static void trigger_create_kthread_locked (void ) +{ +lockdep_assert_held (&trigger_data_kthread_mutex); + +if (!trigger_kthread) { +struct task_struct *kthread; + + kthread =kthread_create (trigger_kthread_fn,NULL , +"trigger_data_free" ); +if (!IS_ERR (kthread)) +WRITE_ONCE (trigger_kthread, kthread); + } +} + +static void trigger_data_free_queued_locked (void ) +{ +struct event_trigger_data *data, *tmp; +struct llist_node *llnodes; + +lockdep_assert_held (&trigger_data_kthread_mutex); + + llnodes =llist_del_all (&trigger_data_free_list); +if (!llnodes) +return ; + +tracepoint_synchronize_unregister (); + +llist_for_each_entry_safe (data, tmp, llnodes, llist) +kfree (data); +} +/* Bulk garbage collection of event_trigger_data elements */ static int trigger_kthread_fn (void *ignore) {
@@ -56,30 +89,50 @@ void trigger_data_free(struct event_trigif (data->cmd_ops->set_filter) data->cmd_ops->set_filter (NULL , data,NULL ); +/* +* Boot-time trigger registration can fail before kthread creation +* works. Keep the deferred-free semantics during boot and let late +* init start the kthread to drain the list. +*/ +if (system_state ==SYSTEM_BOOTING && !trigger_kthread) { +llist_add (&data->llist, &trigger_data_free_list); +return ; + } +if (unlikely (!trigger_kthread)) {guard (mutex)(&trigger_data_kthread_mutex); + +trigger_create_kthread_locked ();/* Check again after taking mutex */ if (!trigger_kthread) { -struct task_struct *kthread; - - kthread =kthread_create (trigger_kthread_fn,NULL , -"trigger_data_free" ); -if (!IS_ERR (kthread)) -WRITE_ONCE (trigger_kthread, kthread); +llist_add (&data->llist, &trigger_data_free_list); +/* Drain the queued frees synchronously if creation failed. */ +trigger_data_free_queued_locked (); +return ; } } -if (!trigger_kthread) { -/* Do it the slow way */ -tracepoint_synchronize_unregister (); -kfree (data); -return ; - } -llist_add (&data->llist, &trigger_data_free_list);wake_up_process (trigger_kthread); } +static int __init trigger_data_free_init (void ) +{ +guard (mutex)(&trigger_data_kthread_mutex); + +if (llist_empty (&trigger_data_free_list)) +return 0 ; + +trigger_create_kthread_locked (); +if (trigger_kthread) +wake_up_process (trigger_kthread); +else +trigger_data_free_queued_locked (); + +return 0 ; +} +late_initcall (trigger_data_free_init); +static inline void data_ops_trigger (struct event_trigger_data *data,struct trace_buffer *buffer,void *rec,struct ring_buffer_event *event)
Greg Kroah-Hartman
maintainerPATCH 199/342 tracing: Fix potential deadlock in cpu hotplug with osnoise
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luo Haiyang <[email protected]>
commit 1f9885732248d22f788e4992c739a98c88ab8a55 upstream.
The following sequence may leads deadlock in cpu hotplug:
task1 task2 task3
----- ----- ----- mutex_lock(&interface_lock)
[CPU GOING OFFLINE]
cpus_write_lock();
osnoise_cpu_die();
kthread_stop(task3);
wait_for_completion();
osnoise_sleep();
mutex_lock(&interface_lock); cpus_read_lock();
[DEAD LOCK]
Fix by swap the order of cpus_read_lock() and mutex_lock(&interface_lock).
--- kernel/trace/trace_osnoise.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
kernel/trace/trace_osnoise.c +5 -5
@@ -2073,8 +2073,8 @@ static void osnoise_hotplug_workfn(strucif (!osnoise_has_registered_instances ())return ; -guard (mutex)(&interface_lock);guard (cpus_read_lock)(); +guard (mutex)(&interface_lock);if (!cpu_online (cpu))return ;
@@ -2237,11 +2237,11 @@ static ssize_t osnoise_options_write(strif (running)stop_per_cpu_kthreads (); -mutex_lock (&interface_lock);/* * avoid CPU hotplug operations that might read options. */ cpus_read_lock (); +mutex_lock (&interface_lock); retval = cnt;
@@ -2257,8 +2257,8 @@ static ssize_t osnoise_options_write(strclear_bit (option, &osnoise_options); } -cpus_read_unlock ();mutex_unlock (&interface_lock); +cpus_read_unlock ();if (running)start_per_cpu_kthreads ();
@@ -2345,16 +2345,16 @@ osnoise_cpus_write(struct file *filp, coif (running)stop_per_cpu_kthreads (); -mutex_lock (&interface_lock);/* * osnoise_cpumask is read by CPU hotplug operations. */ cpus_read_lock (); +mutex_lock (&interface_lock);cpumask_copy (&osnoise_cpumask, osnoise_cpumask_new); -cpus_read_unlock ();mutex_unlock (&interface_lock); +cpus_read_unlock ();if (running)start_per_cpu_kthreads ();
Greg Kroah-Hartman
maintainerPATCH 200/342 drm/xe: always keep track of remap prev/next
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Auld <[email protected]>
commit bfe9e314d7574d1c5c851972e7aee342733819d2 upstream.
During 3D workload, user is reporting hitting:
[ 413.361679] WARNING: drivers/gpu/drm/xe/xe_vm.c:1217 at vm_bind_ioctl_ops_unwind+0x1e2/0x2e0 [xe], CPU#7: vkd3d_queue/9925 [ 413.361944] CPU: 7 UID: 1000 PID: 9925 Comm: vkd3d_queue Kdump: loaded Not tainted 7.0.0-070000rc3-generic #202603090038 PREEMPT(lazy) [ 413.361949] RIP: 0010:vm_bind_ioctl_ops_unwind+0x1e2/0x2e0 [xe] [ 413.362074] RSP: 0018:ffffd4c25c3df930 EFLAGS: 00010282 [ 413.362077] RAX: 0000000000000000 RBX: ffff8f3ee817ed10 RCX: 0000000000000000 [ 413.362078] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 [ 413.362079] RBP: ffffd4c25c3df980 R08: 0000000000000000 R09: 0000000000000000 [ 413.362081] R10: 0000000000000000 R11: 0000000000000000 R12: ffff8f41fbf99380 [ 413.362082] R13: ffff8f3ee817e968 R14: 00000000ffffffef R15: ffff8f43d00bd380 [ 413.362083] FS: 00000001040ff6c0(0000) GS:ffff8f4696d89000(0000) knlGS:00000000330b0000 [ 413.362085] CS: 0010 DS: 002b ES: 002b CR0: 0000000080050033 [ 413.362086] CR2: 00007ddfc4747000 CR3: 00000002e6262005 CR4: 0000000000f72ef0 [ 413.362088] PKRU: 55555554 [ 413.362089] Call Trace: [ 413.362092] <TASK> [ 413.362096] xe_vm_bind_ioctl+0xa9a/0xc60 [xe]
Which seems to hint that the vma we are re-inserting for the ops unwind is either invalid or overlapping with something already inserted in the vm. It shouldn't be invalid since this is a re-insertion, so must have worked before. Leaving the likely culprit as something already placed where we want to insert the vma.
Following from that, for the case where we do something like a rebind in the middle of a vma, and one or both mapped ends are already compatible, we skip doing the rebind of those vma and set next/prev to NULL. As well as then adjust the original unmap va range, to avoid unmapping the ends. However, if we trigger the unwind path, we end up with three va, with the two ends never being removed and the original va range in the middle still being the shrunken size.
If this occurs, one failure mode is when another unwind op needs to interact with that range, which can happen with a vector of binds. For example, if we need to re-insert something in place of the original va. In this case the va is still the shrunken version, so when removing it and then doing a re-insert it can overlap with the ends, which were never removed, triggering a warning like above, plus leaving the vm in a bad state.
With that, we need two things here:
1) Stop nuking the prev/next tracking for the skip cases. Instead relying on checking for skip prev/next, where needed. That way on the unwind path, we now correctly remove both ends.
2) Undo the unmap va shrinkage, on the unwind path. With the two ends now removed the unmap va should expand back to the original size again, before re-insertion.
v2:
- Update the explanation in the commit message, based on an actual IGT of triggering this issue, rather than conjecture.
- Also undo the unmap shrinkage, for the skip case. With the two ends now removed, the original unmap va range should expand back to the original range.
v3:
- Track the old start/range separately. vma_size/start() uses the va info directly.
--- drivers/gpu/drm/xe/xe_pt.c | 12 ++++++------ drivers/gpu/drm/xe/xe_vm.c | 22 ++++++++++++++++++---- drivers/gpu/drm/xe/xe_vm_types.h | 4 ++++ 3 files changed, 28 insertions(+), 10 deletions(-)
drivers/gpu/drm/xe/xe_pt.c +6 -6
@@ -1442,9 +1442,9 @@ static int op_check_svm_userptr(struct x err =vma_check_userptr (vm, op->map.vma, pt_update);break ;case DRM_GPUVA_OP_REMAP : -if (op->remap.prev) +if (op->remap.prev && !op->remap.skip_prev) err =vma_check_userptr (vm, op->remap.prev, pt_update); -if (!err && op->remap.next) +if (!err && op->remap.next && !op->remap.skip_next) err =vma_check_userptr (vm, op->remap.next, pt_update);break ;case DRM_GPUVA_OP_UNMAP :
@@ -2029,12 +2029,12 @@ static int op_prepare(struct xe_vm *vm, err =unbind_op_prepare (tile, pt_update_ops, old); -if (!err && op->remap.prev) { +if (!err && op->remap.prev && !op->remap.skip_prev) { err =bind_op_prepare (vm, tile, pt_update_ops, op->remap.prev, false); pt_update_ops->wait_vm_bookkeep = true; } -if (!err && op->remap.next) { +if (!err && op->remap.next && !op->remap.skip_next) { err =bind_op_prepare (vm, tile, pt_update_ops, op->remap.next, false); pt_update_ops->wait_vm_bookkeep = true;
@@ -2258,10 +2258,10 @@ static void op_commit(struct xe_vm *vm,unbind_op_commit (vm, tile, pt_update_ops, old, fence, fence2); -if (op->remap.prev) +if (op->remap.prev && !op->remap.skip_prev)bind_op_commit (vm, tile, pt_update_ops, op->remap.prev, fence, fence2, false); -if (op->remap.next) +if (op->remap.next && !op->remap.skip_next)bind_op_commit (vm, tile, pt_update_ops, op->remap.next, fence, fence2, false);break ;
drivers/gpu/drm/xe/xe_vm.c +18 -4
@@ -2532,7 +2532,6 @@ static int xe_vma_op_commit(struct xe_vmif (!err && op->remap.skip_prev) { op->remap.prev->tile_present = tile_present; - op->remap.prev =NULL ; } }if (op->remap.next) {
@@ -2542,11 +2541,13 @@ static int xe_vma_op_commit(struct xe_vmif (!err && op->remap.skip_next) { op->remap.next->tile_present = tile_present; - op->remap.next =NULL ; } } -/* Adjust for partial unbind after removing VMA from VM */ +/* +* Adjust for partial unbind after removing VMA from VM. In case +* of unwind we might need to undo this later. +*/ if (!err) { op->base.remap.unmap->va->va.addr = op->remap.start; op->base.remap.unmap->va->va.range = op->remap.range;
@@ -2665,6 +2666,8 @@ static int vm_bind_ioctl_ops_parse(struc op->remap.start =xe_vma_start (old); op->remap.range =xe_vma_size (old); + op->remap.old_start = op->remap.start; + op->remap.old_range = op->remap.range; flags |= op->base.remap.unmap->va->flags &XE_VMA_CREATE_MASK ;if (op->base.remap.prev) {
@@ -2812,8 +2815,19 @@ static void xe_vma_op_unwind(struct xe_vxe_svm_notifier_lock (vm); vma->gpuva.flags &= ~XE_VMA_DESTROYED ;xe_svm_notifier_unlock (vm); -if (post_commit) +if (post_commit) { +/* +* Restore the old va range, in case of the +* prev/next skip optimisation. Otherwise what +* we re-insert here could be smaller than the +* original range. +*/ + op->base.remap.unmap->va->va.addr = + op->remap.old_start; + op->base.remap.unmap->va->va.range = + op->remap.old_range;xe_vm_insert_vma (vm, vma); + } }break ; }
drivers/gpu/drm/xe/xe_vm_types.h +4 -0
@@ -360,6 +360,10 @@ struct xe_vma_op_remap {u64 start;/** @range: range of the VMA unmap */ u64 range; +/** @old_start: Original start of the VMA we unmap */ +u64 old_start; +/** @old_range: Original range of the VMA we unmap */ +u64 old_range;/** @skip_prev: skip prev rebind */ bool skip_prev;/** @skip_next: skip next rebind */
Greg Kroah-Hartman
maintainerPATCH 201/342 ksmbd: replace hardcoded hdr2_len with offsetof() in smb2_calc_max_out_buf_len()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
commit 0e55f63dd08f09651d39e1b709a91705a8a0ddcb upstream.
After this commit (e2b76ab8b5c9 "ksmbd: add support for read compound"), response buffer management was changed to use dynamic iov array. In the new design, smb2_calc_max_out_buf_len() expects the second argument (hdr2_len) to be the offset of ->Buffer field in the response structure, not a hardcoded magic number.
Fix the remaining call sites to use the correct offsetof() value.
--- fs/smb/server/smb2pdu.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-)
fs/smb/server/smb2pdu.c +12 -8
@@ -4445,8 +4445,9 @@ int smb2_query_dir(struct ksmbd_work *wo d_info.wptr = (char *)rsp->Buffer; d_info.rptr = (char *)rsp->Buffer; d_info.out_buf_len = -smb2_calc_max_out_buf_len (work,8 , -le32_to_cpu (req->OutputBufferLength)); +smb2_calc_max_out_buf_len (work, + offsetof(struct smb2_query_directory_rsp , Buffer), +le32_to_cpu (req->OutputBufferLength));if (d_info.out_buf_len <0 ) { rc = -EINVAL ; goto err_out;
@@ -4713,8 +4714,9 @@ static int smb2_get_ea(struct ksmbd_work } buf_free_len = -smb2_calc_max_out_buf_len (work,8 , -le32_to_cpu (req->OutputBufferLength)); +smb2_calc_max_out_buf_len (work, + offsetof(struct smb2_query_info_rsp , Buffer), +le32_to_cpu (req->OutputBufferLength));if (buf_free_len <0 )return -EINVAL ;
@@ -5040,8 +5042,9 @@ static int get_file_stream_info(struct k file_info = (struct smb2_file_stream_info *)rsp->Buffer; buf_free_len = -smb2_calc_max_out_buf_len (work,8 , -le32_to_cpu (req->OutputBufferLength)); +smb2_calc_max_out_buf_len (work, + offsetof(struct smb2_query_info_rsp , Buffer), +le32_to_cpu (req->OutputBufferLength));if (buf_free_len <0 ) goto out;
@@ -8190,8 +8193,9 @@ int smb2_ioctl(struct ksmbd_work *work) buffer = (char *)req +le32_to_cpu (req->InputOffset); cnt_code =le32_to_cpu (req->CtlCode); - ret =smb2_calc_max_out_buf_len (work,48 , -le32_to_cpu (req->MaxOutputResponse)); + ret =smb2_calc_max_out_buf_len (work, + offsetof(struct smb2_ioctl_rsp , Buffer), +le32_to_cpu (req->MaxOutputResponse));if (ret <0 ) { rsp->hdr.Status =STATUS_INVALID_PARAMETER ; goto out;
Greg Kroah-Hartman
maintainerPATCH 202/342 ksmbd: fix potencial OOB in get_file_all_info() for compound requests
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
commit beef2634f81f1c086208191f7228bce1d366493d upstream.
When a compound request consists of QUERY_DIRECTORY + QUERY_INFO (FILE_ALL_INFORMATION) and the first command consumes nearly the entire max_trans_size, get_file_all_info() would blindly call smbConvertToUTF16() with PATH_MAX, causing out-of-bounds write beyond the response buffer. In get_file_all_info(), there was a missing validation check for the client-provided OutputBufferLength before copying the filename into FileName field of the smb2_file_all_info structure.
If the filename length exceeds the available buffer space, it could lead to potential buffer overflows or memory corruption during smbConvertToUTF16 conversion. This calculating the actual free buffer size using smb2_calc_max_out_buf_len() and returning -EINVAL if the buffer is insufficient and updating smbConvertToUTF16 to use the actual filename length (clamped by PATH_MAX) to ensure a safe copy operation.
--- fs/smb/server/smb2pdu.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-)
fs/smb/server/smb2pdu.c +14 -2
@@ -4933,7 +4933,8 @@ static int get_file_all_info(struct ksmbint conv_len;char *filename;u64 time; -int ret; +int ret, buf_free_len, filename_len; +struct smb2_query_info_req *req =ksmbd_req_buf_next (work);if (!(fp->daccess &FILE_READ_ATTRIBUTES_LE )) { ksmbd_debug(SMB, "no right to read the attributes : 0x%x\n",
@@ -4945,6 +4946,16 @@ static int get_file_all_info(struct ksmbif (IS_ERR (filename))return PTR_ERR (filename); + filename_len =strlen (filename); + buf_free_len =smb2_calc_max_out_buf_len (work, + offsetof(struct smb2_query_info_rsp , Buffer) + + offsetof(struct smb2_file_all_info , FileName), +le32_to_cpu (req->OutputBufferLength)); +if (buf_free_len < (filename_len +1 ) *2 ) { +kfree (filename); +return -EINVAL ; + } + ret =vfs_getattr (&fp->filp->f_path, &stat,STATX_BASIC_STATS ,AT_STATX_SYNC_AS_STAT );if (ret) {
@@ -4988,7 +4999,8 @@ static int get_file_all_info(struct ksmb file_info->Mode = fp->coption; file_info->AlignmentRequirement =0 ; conv_len =smbConvertToUTF16 ((__le16 *)file_info->FileName, filename, -PATH_MAX , conn->local_nls,0 ); +min (filename_len,PATH_MAX ), + conn->local_nls,0 ); conv_len *=2 ; file_info->FileNameLength =cpu_to_le32 (conv_len); rsp->OutputBufferLength =
Greg Kroah-Hartman
maintainerPATCH 203/342 ksmbd: fix memory leaks and NULL deref in smb2_lock()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Werner Kasselman <[email protected]>
commit 309b44ed684496ed3f9c5715d10b899338623512 upstream.
smb2_lock() has three error handling issues after list_del() detaches smb_lock from lock_list at no_check_cl:
1) If vfs_lock_file() returns an unexpected error in the non-UNLOCK path, goto out leaks smb_lock and its flock because the out:
handler only iterates lock_list and rollback_list, neither of which contains the detached smb_lock.
2) If vfs_lock_file() returns -ENOENT in the UNLOCK path, goto out leaks smb_lock and flock for the same reason. The error code returned to the dispatcher is also stale.
3) In the rollback path, smb_flock_init() can return NULL on allocation failure. The result is dereferenced unconditionally, causing a kernel NULL pointer dereference. Add a NULL check to prevent the crash and clean up the bookkeeping; the VFS lock itself cannot be rolled back without the allocation and will be released at file or connection teardown.
Fix cases 1 and 2 by hoisting the locks_free_lock()/kfree() to before the if(!rc) check in the UNLOCK branch so all exit paths share one free site, and by freeing smb_lock and flock before goto out in the non-UNLOCK branch. Propagate the correct error code in both cases. Fix case 3 by wrapping the VFS unlock in an if(rlock) guard and adding a NULL check for locks_free_lock(rlock) in the shared cleanup.
Found via call-graph analysis using sqry.
--- fs/smb/server/smb2pdu.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-)
fs/smb/server/smb2pdu.c +19 -10
@@ -7600,14 +7600,15 @@ retry: rc =vfs_lock_file (filp, smb_lock->cmd, flock,NULL ); skip:if (smb_lock->flags &SMB2_LOCKFLAG_UNLOCK ) { +locks_free_lock (flock); +kfree (smb_lock);if (!rc) {ksmbd_debug (SMB ,"File unlocked\n" ); }else if (rc == -ENOENT ) { rsp->hdr.Status =STATUS_NOT_LOCKED ; + err = rc; goto out; } -locks_free_lock (flock); -kfree (smb_lock); }else {if (rc ==FILE_LOCK_DEFERRED ) {void **argv;
@@ -7676,6 +7677,9 @@ skip:spin_unlock (&work->conn->llist_lock);ksmbd_debug (SMB ,"successful in taking lock\n" ); }else { +locks_free_lock (flock); +kfree (smb_lock); + err = rc; goto out; } }
@@ -7706,13 +7710,17 @@ out:struct file_lock *rlock =NULL ; rlock =smb_flock_init (filp); - rlock->c.flc_type =F_UNLCK ; - rlock->fl_start = smb_lock->start; - rlock->fl_end = smb_lock->end; - - rc =vfs_lock_file (filp,F_SETLK , rlock,NULL ); -if (rc) -pr_err ("rollback unlock fail : %d\n" , rc); +if (rlock) { + rlock->c.flc_type =F_UNLCK ; + rlock->fl_start = smb_lock->start; + rlock->fl_end = smb_lock->end; + + rc =vfs_lock_file (filp,F_SETLK , rlock,NULL ); +if (rc) +pr_err ("rollback unlock fail : %d\n" , rc); + }else { +pr_err ("rollback unlock alloc failed\n" ); + }list_del (&smb_lock->llist);spin_lock (&work->conn->llist_lock);
@@ -7722,7 +7730,8 @@ out:spin_unlock (&work->conn->llist_lock);locks_free_lock (smb_lock->fl); -locks_free_lock (rlock); +if (rlock) +locks_free_lock (rlock);kfree (smb_lock); } out2:
Greg Kroah-Hartman
maintainerPATCH 204/342 ksmbd: do not expire session on binding failure
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hyunwoo Kim <[email protected]>
commit 9bbb19d21ded7d78645506f20d8c44895e3d0fb9 upstream.
When a multichannel session binding request fails (e.g. wrong password), the error path unconditionally sets sess->state = SMB2_SESSION_EXPIRED. However, during binding, sess points to the target session looked up via ksmbd_session_lookup_slowpath() -- which belongs to another connection's user. This allows a remote attacker to invalidate any active session by simply sending a binding request with a wrong password (DoS).
Fix this by skipping session expiration when the failed request was a binding attempt, since the session does not belong to the current connection. The reference taken by ksmbd_session_lookup_slowpath() is still correctly released via ksmbd_user_session_put().
--- fs/smb/server/smb2pdu.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
fs/smb/server/smb2pdu.c +8 -2
@@ -1938,8 +1938,14 @@ out_err:if (sess->user && sess->user->flags &KSMBD_USER_FLAG_DELAY_SESSION ) try_delay = true; - sess->last_active = jiffies; - sess->state =SMB2_SESSION_EXPIRED ; +/* +* For binding requests, session belongs to another +* connection. Do not expire it. +*/ +if (!(req->Flags &SMB2_SESSION_REQ_FLAG_BINDING )) { + sess->last_active = jiffies; + sess->state =SMB2_SESSION_EXPIRED ; + }ksmbd_user_session_put (sess); work->sess =NULL ;if (try_delay) {
Greg Kroah-Hartman
maintainerPATCH 205/342 Revert "ALSA: hda/intel: Add MSI X870E Tomahawk to denylist"
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mario Limonciello <[email protected]>
commit ed4da361bf943b9041fc63e5cb6af01b3c0de978 upstream.
commit 30b3211aa2416 ("ALSA: hda/intel: Add MSI X870E Tomahawk to denylist") was added to silence a warning, but this effectively reintroduced commit df42ee7e22f03 ("ALSA: hda: Add ASRock X670E Taichi to denylist") which was already reported to cause problems and reverted in commit ee8f1613596ad ("Revert "ALSA: hda:
Add ASRock X670E Taichi to denylist"")
Revert it yet again.
--- sound/hda/controllers/intel.c | 1 - 1 file changed, 1 deletion(-)
sound/hda/controllers/intel.c +0 -1
@@ -2077,7 +2077,6 @@ static const struct pci_device_id driver { PCI_DEVICE_SUB(0x1022, 0x1487, 0x1043, 0x874f) }, /* ASUS ROG Zenith II / Strix */ { PCI_DEVICE_SUB(0x1022, 0x1487, 0x1462, 0xcb59) }, /* MSI TRX40 Creator */ { PCI_DEVICE_SUB(0x1022, 0x1487, 0x1462, 0xcb60) }, /* MSI TRX40 */ - { PCI_DEVICE_SUB(0x1022, 0x15e3, 0x1462, 0xee59) }, /* MSI X870E Tomahawk WiFi */ {} };
Greg Kroah-Hartman
maintainerPATCH 206/342 ALSA: hda/realtek: add quirk for ASUS Strix G16 G615JMR
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhang Heng <[email protected]>
commit 0bdf27abaf8940592207be939142451436afe39f upstream.
The machine is equipped with ALC294 and requires the ALC287_FIXUP_TXNW2781_I2C_ASUS quirk for the amplifier to work properly. Since the machine's PCI SSID is also 1043:1204, HDA_CODEC_QUIRK is used to retain the previous quirk.
--- sound/hda/codecs/realtek/alc269.c | 1 + 1 file changed, 1 insertion(+)
sound/hda/codecs/realtek/alc269.c +1 -0
@@ -7203,6 +7203,7 @@ static const struct hda_quirk alc269_fixSND_PCI_QUIRK (0x1043 ,0x115d ,"Asus 1015E" ,ALC269_FIXUP_LIMIT_INT_MIC_BOOST ),SND_PCI_QUIRK (0x1043 ,0x1194 ,"ASUS UM3406KA" ,ALC287_FIXUP_CS35L41_I2C_2 ),SND_PCI_QUIRK (0x1043 ,0x11c0 ,"ASUS X556UR" ,ALC255_FIXUP_ASUS_MIC_NO_PRESENCE ), +HDA_CODEC_QUIRK (0x1043 ,0x1204 ,"ASUS Strix G16 G615JMR" ,ALC287_FIXUP_TXNW2781_I2C_ASUS ),SND_PCI_QUIRK (0x1043 ,0x1204 ,"ASUS Strix G615JHR_JMR_JPR" ,ALC287_FIXUP_TAS2781_I2C ),SND_PCI_QUIRK (0x1043 ,0x1214 ,"ASUS Strix G615LH_LM_LP" ,ALC287_FIXUP_TAS2781_I2C ), SND_PCI_QUIRK(0x1043, 0x125e, "ASUS Q524UQK", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
Greg Kroah-Hartman
maintainerPATCH 207/342 ALSA: firewire-lib: fix uninitialized local variable
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexey Nepomnyashih <[email protected]>
commit bb120ad57def62e3f23e3d999c5fbed11f610993 upstream.
Similar to commit d8dc8720468a ("ALSA: firewire-lib: fix uninitialized local variable"), the local variable curr_cycle_time in process_rx_packets() is declared without initialization.
When the tracepoint event is not probed, the variable may appear to be used without being initialized. In practice the value is only relevant when the tracepoint is enabled, however initializing it avoids potential use of an uninitialized value and improves code safety.
Initialize curr_cycle_time to zero.
--- sound/firewire/amdtp-stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/firewire/amdtp-stream.c +1 -1
@@ -1179,7 +1179,7 @@ static void process_rx_packets(struct fwstruct pkt_desc *desc = s->packet_descs_cursor;unsigned int pkt_header_length;unsigned int packets; -u32 curr_cycle_time; +u32 curr_cycle_time =0 ;bool need_hw_irq;int i;
Greg Kroah-Hartman
maintainerPATCH 208/342 accel/ivpu: Add disable clock relinquish workaround for NVL-A0
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karol Wachowski <[email protected]>
commit e8ab57b56402697a9bef50b71aecc613f0d61846 upstream.
Turn on disable clock relinquish workaround for Nova Lake A0. Without this workaround NPU may not power off correctly after inference, leading to unexpected system behavior.
--- drivers/accel/ivpu/ivpu_drv.h | 1 + drivers/accel/ivpu/ivpu_hw.c | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-)
drivers/accel/ivpu/ivpu_drv.h +1 -0
@@ -35,6 +35,7 @@#define IVPU_HW_IP_60XX 60#define IVPU_HW_IP_REV_LNL_B0 4 +#define IVPU_HW_IP_REV_NVL_A0 0#define IVPU_HW_BTRS_MTL 1#define IVPU_HW_BTRS_LNL 2
drivers/accel/ivpu/ivpu_hw.c +4 -2
@@ -70,8 +70,10 @@ static void wa_init(struct ivpu_device *vdev)if (ivpu_hw_btrs_gen (vdev) ==IVPU_HW_BTRS_MTL ) vdev->wa.interrupt_clear_with_0 =ivpu_hw_btrs_irqs_clear_with_0_mtl (vdev); -if (ivpu_device_id (vdev) ==PCI_DEVICE_ID_LNL && -ivpu_revision (vdev) <IVPU_HW_IP_REV_LNL_B0 ) +if ((ivpu_device_id (vdev) ==PCI_DEVICE_ID_LNL && +ivpu_revision (vdev) <IVPU_HW_IP_REV_LNL_B0 ) || + (ivpu_device_id (vdev) ==PCI_DEVICE_ID_NVL && +ivpu_revision (vdev) ==IVPU_HW_IP_REV_NVL_A0 )) vdev->wa.disable_clock_relinquish = true;if (ivpu_test_mode &IVPU_TEST_MODE_CLK_RELINQ_ENABLE )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 209/342 ASoC: codecs: wcd934x: fix typo in dt parsing
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Srinivas Kandagatla <[email protected]>
commit cfb385a8dc88d86a805a5682eaa68f59fa5c0ec3 upstream.
Looks like we ended up with a typo during device tree data parsing as part of 4f16b6351bbff ("ASoC: codecs: wcd: add common helper for wcd codecs") patch.
This will result in not parsing the device tree data and results in
zero mic bias values.
Fix this by calling wcd_dt_parse_micbias_info instead of wcd_dt_parse_mbhc_data.
--- sound/soc/codecs/wcd934x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/codecs/wcd934x.c +1 -1
@@ -2172,7 +2172,7 @@ static int wcd934x_init_dmic(struct snd_u32 def_dmic_rate, dmic_clk_drv;int ret; - ret =wcd_dt_parse_mbhc_data (comp->dev, &wcd->mbhc_cfg); + ret =wcd_dt_parse_micbias_info (&wcd->common);if (ret)return ret;
Greg Kroah-Hartman
maintainerPATCH 210/342 ASoC: sma1307: fix double free of devm_kzalloc() memory
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
commit fe757092d2329c397ecb32f2bf68a5b1c4bd9193 upstream.
A previous change added NULL checks and cleanup for allocation failures in sma1307_setting_loaded().
However, the cleanup for mode_set entries is wrong. Those entries are allocated with devm_kzalloc(), so they are device-managed resources and must not be freed with kfree(). Manually freeing them in the error path can lead to a double free when devres later releases the same memory.
Drop the manual kfree() loop and let devres handle the cleanup.
--- sound/soc/codecs/sma1307.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
sound/soc/codecs/sma1307.c +4 -2
@@ -1759,8 +1759,10 @@ static void sma1307_setting_loaded(struc sma1307->set.mode_size *2 *sizeof (int ), GFP_KERNEL);if (!sma1307->set.mode_set[i]) { -for (int j =0 ; j < i; j++) -kfree (sma1307->set.mode_set[j]); +for (int j =0 ; j < i; j++) { +devm_kfree (sma1307->dev, sma1307->set.mode_set[j]); + sma1307->set.mode_set[j] =NULL ; + } sma1307->set.status = false;return ; }
Greg Kroah-Hartman
maintainerPATCH 211/342 ASoC: SOF: ipc4-topology: Allow bytes controls without initial payload
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peter Ujfalusi <[email protected]>
commit d40a198e2b7821197c5c77b89d0130cc90f400f5 upstream.
It is unexpected, but allowed to have no initial payload for a bytes control and the code is prepared to handle this case, but the size check missed this corner case.
Update the check for minimal size to allow the initial size to be 0.
--- sound/soc/sof/ipc4-topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/sof/ipc4-topology.c +1 -1
@@ -2889,7 +2889,7 @@ static int sof_ipc4_control_load_bytes(sreturn -EINVAL ; } -if (scontrol->priv_size <sizeof (struct sof_abi_hdr )) { +if (scontrol->priv_size && scontrol->priv_size <sizeof (struct sof_abi_hdr )) {dev_err (sdev->dev,"bytes control %s initial data size %zu is insufficient.\n" , scontrol->name, scontrol->priv_size);
Greg Kroah-Hartman
maintainerPATCH 212/342 can: gw: fix OOB heap access in cgw_csum_crc8_rel()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ali Norouzi <[email protected]>
commit b9c310d72783cc2f30d103eed83920a5a29c671a upstream.
cgw_csum_crc8_rel() correctly computes bounds-safe indices via calc_idx():
int from = calc_idx(crc8->from_idx, cf->len);
int to = calc_idx(crc8->to_idx, cf->len);
int res = calc_idx(crc8->result_idx, cf->len);
if (from < 0 || to < 0 || res < 0)
return;However, the loop and the result write then use the raw s8 fields directly instead of the computed variables:
for (i = crc8->from_idx; ...) /* BUG: raw negative index */
cf->data[crc8->result_idx] = ...; /* BUG: raw negative index */With from_idx = to_idx = result_idx = -64 on a 64-byte CAN FD frame, calc_idx(-64, 64) = 0 so the guard passes, but the loop iterates with i = -64, reading cf->data[-64], and the write goes to cf->data[-64]. This write might end up to 56 (7.0-rc) or 40 (<= 6.19) bytes before the start of the canfd_frame on the heap.
The companion function cgw_csum_xor_rel() uses from/to/res correctly throughout; fix cgw_csum_crc8_rel() to match.
Confirmed with KASAN on linux-7.0-rc2:
BUG: KASAN: slab-out-of-bounds in cgw_csum_crc8_rel+0x515/0x5b0 Read of size 1 at addr ffff8880076619c8 by task poc_cgw_oob/62
To configure the can-gw crc8 checksums CAP_NET_ADMIN is needed.
--- net/can/gw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
net/can/gw.c +3 -3
@@ -374,10 +374,10 @@ static void cgw_csum_crc8_rel(struct canreturn ;if (from <= to) { -for (i = crc8->from_idx; i <= crc8->to_idx; i++) +for (i = from; i <= to; i++) crc = crc8->crctab[crc ^ cf->data[i]]; }else { -for (i = crc8->from_idx; i >= crc8->to_idx; i--) +for (i = from; i >= to; i--) crc = crc8->crctab[crc ^ cf->data[i]]; }
@@ -396,7 +396,7 @@ static void cgw_csum_crc8_rel(struct canbreak ; } - cf->data[crc8->result_idx] = crc ^ crc8->final_xor_val; + cf->data[res] = crc ^ crc8->final_xor_val; } static void cgw_csum_crc8_pos(struct canfd_frame *cf,
Greg Kroah-Hartman
maintainerPATCH 213/342 can: isotp: fix tx.buf use-after-free in isotp_sendmsg()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Oliver Hartkopp <[email protected]>
commit 424e95d62110cdbc8fd12b40918f37e408e35a92 upstream.
isotp_sendmsg() uses only cmpxchg() on so->tx.state to serialize access to so->tx.buf. isotp_release() waits for ISOTP_IDLE via wait_event_interruptible() and then calls kfree(so->tx.buf).
If a signal interrupts the wait_event_interruptible() inside close() while tx.state is ISOTP_SENDING, the loop exits early and release proceeds to force ISOTP_SHUTDOWN and continues to kfree(so->tx.buf) while sendmsg may still be reading so->tx.buf for the final CAN frame in isotp_fill_dataframe().
The so->tx.buf can be allocated once when the standard tx.buf length needs to be extended. Move the kfree() of this potentially extended tx.buf to sk_destruct time when either isotp_sendmsg() and isotp_release() are done.
--- net/can/isotp.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-)
net/can/isotp.c +18 -6
@@ -1230,12 +1230,6 @@ static int isotp_release(struct socket * so->ifindex =0 ; so->bound =0 ; -if (so->rx.buf != so->rx.sbuf) -kfree (so->rx.buf); - -if (so->tx.buf != so->tx.sbuf) -kfree (so->tx.buf); -sock_orphan (sk); sock->sk =NULL ;
@@ -1604,6 +1598,21 @@ static int isotp_notifier(struct notifiereturn NOTIFY_DONE ; } +static void isotp_sock_destruct (struct sock *sk) +{ +struct isotp_sock *so =isotp_sk (sk); + +/* do the standard CAN sock destruct work */ +can_sock_destruct (sk); + +/* free potential extended PDU buffers */ +if (so->rx.buf != so->rx.sbuf) +kfree (so->rx.buf); + +if (so->tx.buf != so->tx.sbuf) +kfree (so->tx.buf); +} +static int isotp_init (struct sock *sk) {struct isotp_sock *so =isotp_sk (sk);
@@ -1648,6 +1657,9 @@ static int isotp_init(struct sock *sk)list_add_tail (&so->notifier, &isotp_notifier_list);spin_unlock (&isotp_notifier_lock); +/* re-assign default can_sock_destruct() reference */ + sk->sk_destruct = isotp_sock_destruct; +return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 214/342 can: netlink: can_changelink(): add missing error handling to call can_ctrlmode_changelink()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marc Kleine-Budde <[email protected]>
commit cadf6019231b614ebbd9ec2a16e5997ecbd8d016 upstream.
In commit e1a5cd9d6665 ("can: netlink: add can_ctrlmode_changelink()") the CAN Control Mode (IFLA_CAN_CTRLMODE) handling was factored out into the can_ctrlmode_changelink() function. But the call to can_ctrlmode_changelink() is missing the error handling.
Add the missing error handling and propagation to the call can_ctrlmode_changelink().
--- drivers/net/can/dev/netlink.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/net/can/dev/netlink.c +3 -1
@@ -601,7 +601,9 @@ static int can_changelink(struct net_dev/* We need synchronization with dev->stop() */ ASSERT_RTNL (); -can_ctrlmode_changelink (dev, data, extack); + err =can_ctrlmode_changelink (dev, data, extack); +if (err) +return err;if (data[IFLA_CAN_BITTIMING ]) {struct can_bittiming bt;
Greg Kroah-Hartman
maintainerPATCH 215/342 cpufreq: Dont skip cpufreq_frequency_table_cpuinfo()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Viresh Kumar <[email protected]>
commit 8f13c0c6cb75cc4421d5a60fc060e9e6fd9d1097 upstream.
The commit 6db0f533d320 ("cpufreq: preserve freq_table_sorted across suspend/hibernate") unintentionally made a change where cpufreq_frequency_table_cpuinfo() isn't getting called anymore for old policies getting re-initialized.
This leads to potentially invalid values of policy->max and policy->cpuinfo_max_freq.
Fix the issue by reverting the original commit and adding the condition for just the sorting function.
--- drivers/cpufreq/cpufreq.c | 9 +++------ drivers/cpufreq/freq_table.c | 4 ++++ 2 files changed, 7 insertions(+), 6 deletions(-)
drivers/cpufreq/cpufreq.c +3 -6
@@ -1421,12 +1421,9 @@ static int cpufreq_policy_online(struct* If there is a problem with its frequency table, take it * offline and drop it. */ -if (policy->freq_table_sorted !=CPUFREQ_TABLE_SORTED_ASCENDING && - policy->freq_table_sorted !=CPUFREQ_TABLE_SORTED_DESCENDING ) { - ret =cpufreq_table_validate_and_sort (policy); -if (ret) - goto out_offline_policy; - } + ret =cpufreq_table_validate_and_sort (policy); +if (ret) + goto out_offline_policy;/* related_cpus should at least include policy->cpus. */ cpumask_copy (policy->related_cpus, policy->cpus);
drivers/cpufreq/freq_table.c +4 -0
@@ -360,6 +360,10 @@ int cpufreq_table_validate_and_sort(struif (policy_has_boost_freq (policy)) policy->boost_supported = true; +if (policy->freq_table_sorted ==CPUFREQ_TABLE_SORTED_ASCENDING || + policy->freq_table_sorted ==CPUFREQ_TABLE_SORTED_DESCENDING ) +return 0 ; +return set_freq_table_sorted (policy); }
Greg Kroah-Hartman
maintainerPATCH 216/342 cpufreq: conservative: Reset requested_freq on limits change
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Viresh Kumar <[email protected]>
commit 6a28fb8cb28b9eb39a392e531d938a889eacafc5 upstream.
A recently reported issue highlighted that the cached requested_freq is not guaranteed to stay in sync with policy->cur. If the platform changes the actual CPU frequency after the governor sets one (e.g. due to platform-specific frequency scaling) and a re-sync occurs later, policy->cur may diverge from requested_freq.
This can lead to incorrect behavior in the conservative governor. For example, the governor may assume the CPU is already running at the maximum frequency and skip further increases even though there is still headroom.
Avoid this by resetting the cached requested_freq to policy->cur on detecting a change in policy limits.
--- drivers/cpufreq/cpufreq_conservative.c | 12 ++++++++++++ drivers/cpufreq/cpufreq_governor.c | 3 +++ drivers/cpufreq/cpufreq_governor.h | 1 + 3 files changed, 16 insertions(+)
drivers/cpufreq/cpufreq_conservative.c +12 -0
@@ -313,6 +313,17 @@ static void cs_start(struct cpufreq_poli dbs_info->requested_freq = policy->cur; } +static void cs_limits (struct cpufreq_policy *policy) +{ +struct cs_policy_dbs_info *dbs_info =to_dbs_info (policy->governor_data); + +/* +* The limits have changed, so may have the current frequency. Reset +* requested_freq to avoid any unintended outcomes due to the mismatch. +*/ + dbs_info->requested_freq = policy->cur; +} +static struct dbs_governor cs_governor = { .gov =CPUFREQ_DBS_GOVERNOR_INITIALIZER ("conservative" ), .kobj_type = { .default_groups = cs_groups },
@@ -322,6 +333,7 @@ static struct dbs_governor cs_governor = .init = cs_init, .exit = cs_exit, .start = cs_start, + .limits = cs_limits, };#define CPU_FREQ_GOV_CONSERVATIVE (cs_governor.gov)
drivers/cpufreq/cpufreq_governor.c +3 -0
@@ -563,6 +563,7 @@ EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_svoid cpufreq_dbs_governor_limits (struct cpufreq_policy *policy) { +struct dbs_governor *gov =dbs_governor_of (policy);struct policy_dbs_info *policy_dbs;/* Protect gov->gdbs_data against cpufreq_dbs_governor_exit() */
@@ -574,6 +575,8 @@ void cpufreq_dbs_governor_limits(structmutex_lock (&policy_dbs->update_mutex);cpufreq_policy_apply_limits (policy);gov_update_sample_delay (policy_dbs,0 ); +if (gov->limits) + gov->limits (policy);mutex_unlock (&policy_dbs->update_mutex); out:
drivers/cpufreq/cpufreq_governor.h +1 -0
@@ -138,6 +138,7 @@ struct dbs_governor {int (*init)(struct dbs_data *dbs_data);void (*exit)(struct dbs_data *dbs_data);void (*start)(struct cpufreq_policy *policy); +void (*limits)(struct cpufreq_policy *policy); };static inline struct dbs_governor *dbs_governor_of (struct cpufreq_policy *policy)
Greg Kroah-Hartman
maintainerPATCH 217/342 kbuild: Delete .builtin-dtbs.S when running make clean
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Charles Mirabile <[email protected]>
commit a76e30c2479ce6ffa2aa6c8a8462897afc82bc90 upstream.
The makefile tries to delete a file named ".builtin-dtb.S" but the file created by scripts/Makefile.vmlinux is actually called ".builtin-dtbs.S".
--- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Makefile +1 -1
@@ -1622,7 +1622,7 @@ CLEAN_FILES += vmlinux.symvers modules-o modules.builtin.ranges vmlinux.o.map vmlinux.unstripped \ compile_commands.json rust/test \ rust-project.json .vmlinux.objs .vmlinux.export.c \ - .builtin-dtbs-list .builtin-dtb.S + .builtin-dtbs-list .builtin-dtbs.S # Directories & files removed with 'make mrproper' MRPROPER_FILES += include/config include/generated \
Greg Kroah-Hartman
maintainerPATCH 218/342 mm/damon/stat: monitor all System RAM resources
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: SeongJae Park <[email protected]>
commit 84481e705ab07ed46e56587fe846af194acacafe upstream.
DAMON_STAT usage document (Documentation/admin-guide/mm/damon/stat.rst) says it monitors the system's entire physical memory. But, it is monitoring only the biggest System RAM resource of the system. When there are multiple System RAM resources, this results in monitoring only an unexpectedly small fraction of the physical memory. For example, suppose the system has a 500 GiB System RAM, 10 MiB non-System RAM, and 500 GiB System RAM resources in order on the physical address space. DAMON_STAT will monitor only the first 500 GiB System RAM. This situation is particularly common on NUMA systems.
Select a physical address range that covers all System RAM areas of the system, to fix this issue and make it work as documented.
--- mm/damon/stat.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 3 deletions(-)
mm/damon/stat.c +50 -3
@@ -145,12 +145,59 @@ static int damon_stat_damon_call_fn(voidreturn 0 ; } +struct damon_stat_system_ram_range_walk_arg { +bool walked; +struct resource res; +}; + +static int damon_stat_system_ram_walk_fn (struct resource *res,void *arg) +{ +struct damon_stat_system_ram_range_walk_arg *a = arg; + +if (!a->walked) { + a->walked = true; + a->res.start = res->start; + } + a->res.end = res->end; +return 0 ; +} + +static unsigned long damon_stat_res_to_core_addr (resource_size_t ra, +unsigned long addr_unit) +{ +/* +* Use div_u64() for avoiding linking errors related with __udivdi3, +* __aeabi_uldivmod, or similar problems. This should also improve the +* performance optimization (read div_u64() comment for the detail). +*/ +if (sizeof (ra) ==8 &&sizeof (addr_unit) ==4 ) +return div_u64 (ra, addr_unit); +return ra / addr_unit; +} + +static int damon_stat_set_monitoring_region (struct damon_target *t, +unsigned long addr_unit,unsigned long min_region_sz) +{ +struct damon_addr_range addr_range; +struct damon_stat_system_ram_range_walk_arg arg = {}; + +walk_system_ram_res (0 ,-1 , &arg, damon_stat_system_ram_walk_fn); +if (!arg.walked) +return -EINVAL ; + addr_range.start =damon_stat_res_to_core_addr ( + arg.res.start, addr_unit); + addr_range.end =damon_stat_res_to_core_addr ( + arg.res.end +1 , addr_unit); +if (addr_range.end <= addr_range.start) +return -EINVAL ; +return damon_set_regions (t, &addr_range,1 , min_region_sz); +} +static struct damon_ctx *damon_stat_build_ctx (void ) {struct damon_ctx *ctx;struct damon_attrs attrs;struct damon_target *target; -unsigned long start =0 , end =0 ; ctx =damon_new_ctx ();if (!ctx)
@@ -188,8 +235,8 @@ static struct damon_ctx *damon_stat_builif (!target) goto free_out;damon_add_target (ctx, target); -if (damon_set_region_biggest_system_ram_default (target, &start, &end, - ctx->min_region_sz)) +if (damon_stat_set_monitoring_region (target, ctx->addr_unit, + ctx->min_region_sz)) goto free_out;return ctx; free_out:
Greg Kroah-Hartman
maintainerPATCH 219/342 thermal: intel: int340x: soc_slider: Set offset only for balanced mode
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Srinivas Pandruvada <[email protected]>
commit 7dfe9846016b15816e287a4650be1ff1b48c5ab4 upstream.
The slider offset can be set via debugfs for balanced mode. The offset should be only applicable in balanced mode. For other modes, it should be 0 when writing to MMIO offset,
--- drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c +7 -1
@@ -176,15 +176,21 @@ static inline void write_soc_slider(strustatic void set_soc_power_profile (struct proc_thermal_device *proc_priv,int slider) { +u8 offset;u64 val; val =read_soc_slider (proc_priv); val &= ~SLIDER_MASK ; val |=FIELD_PREP (SLIDER_MASK , slider) |BIT (SLIDER_ENABLE_BIT ); +if (slider ==SOC_SLIDER_VALUE_MINIMUM || slider ==SOC_SLIDER_VALUE_MAXIMUM ) + offset =0 ; +else + offset = slider_offset; +/* Set the slider offset from module params */ val &= ~SLIDER_OFFSET_MASK ; - val |=FIELD_PREP (SLIDER_OFFSET_MASK , slider_offset); + val |=FIELD_PREP (SLIDER_OFFSET_MASK , offset);write_soc_slider (proc_priv, val); }
Greg Kroah-Hartman
maintainerPATCH 220/342 RDMA/ionic: Preserve and set Ethernet source MAC after ib_ud_header_init()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abhijit Gangurde <[email protected]>
commit a08aaf3968aec5d05cd32c801b8cc0c61da69c41 upstream.
ionic_build_hdr() populated the Ethernet source MAC (hdr->eth.smac_h) by passing the header’s storage directly to rdma_read_gid_l2_fields(). However, ib_ud_header_init() is called after that and re-initializes the UD header, which wipes the previously written smac_h. As a result, packets are emitted with an zero source MAC address on the wire.
Correct the source MAC by reading the GID-derived smac into a temporary buffer and copy it after ib_ud_header_init() completes.
--- drivers/infiniband/hw/ionic/ionic_controlpath.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/infiniband/hw/ionic/ionic_controlpath.c +3 -1
@@ -508,6 +508,7 @@ static int ionic_build_hdr(struct ionic_ {const struct ib_global_route *grh;enum rdma_network_type net; +u8 smac[ETH_ALEN ];u16 vlan;int rc;
@@ -518,7 +519,7 @@ static int ionic_build_hdr(struct ionic_ grh =rdma_ah_read_grh (attr); - rc =rdma_read_gid_l2_fields (grh->sgid_attr, &vlan, &hdr->eth.smac_h[0 ]); + rc =rdma_read_gid_l2_fields (grh->sgid_attr, &vlan, smac);if (rc)return rc;
@@ -536,6 +537,7 @@ static int ionic_build_hdr(struct ionic_if (rc)return rc; +ether_addr_copy (hdr->eth.smac_h, smac);ether_addr_copy (hdr->eth.dmac_h, attr->roce.dmac);if (net ==RDMA_NETWORK_IPV4 ) {
Greg Kroah-Hartman
maintainerPATCH 221/342 platform/x86: ISST: Correct locked bit width
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Srinivas Pandruvada <[email protected]>
commit fbddf68d7b4e1e6da7a78dd7fbd8ec376536584a upstream.
SST-PP locked bit width is set to three bits. It should be only one bit. Use SST_PP_LOCK_WIDTH define instead of SST_PP_LEVEL_WIDTH.
--- drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c +1 -1
@@ -871,7 +871,7 @@ static int isst_if_get_perf_level(void __read_pp_info ("current_level" , perf_level.current_level,SST_PP_STATUS_OFFSET , SST_PP_LEVEL_START, SST_PP_LEVEL_WIDTH, SST_MUL_FACTOR_NONE)_read_pp_info ("locked" , perf_level.locked,SST_PP_STATUS_OFFSET , - SST_PP_LOCK_START, SST_PP_LEVEL_WIDTH, SST_MUL_FACTOR_NONE) + SST_PP_LOCK_START, SST_PP_LOCK_WIDTH, SST_MUL_FACTOR_NONE)_read_pp_info ("feature_state" , perf_level.feature_state,SST_PP_STATUS_OFFSET ,SST_PP_FEATURE_STATE_START ,SST_PP_FEATURE_STATE_WIDTH ,SST_MUL_FACTOR_NONE ) perf_level.enabled = !!(power_domain_info->sst_header.cap_mask & BIT(1));
Greg Kroah-Hartman
maintainerPATCH 222/342 KVM: arm64: Discard PC update state on vcpu reset
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marc Zyngier <[email protected]>
commit 1744a6ef48b9a48f017e3e1a0d05de0a6978396e upstream.
Our vcpu reset suffers from a particularly interesting flaw, as it does not correctly deal with state that will have an effect on the execution flow out of reset.
Take the following completely random example, never seen in the wild and that never resulted in a couple of sleepless nights: /s
- vcpu-A issues a PSCI_CPU_OFF using the SMC conduit
- SMC being a trapped instruction (as opposed to HVC which is always normally executed), we annotate the vcpu as needing to skip the next instruction, which is the SMC itself
- vcpu-A is now safely off
- vcpu-B issues a PSCI_CPU_ON for vcpu-A, providing a starting PC
- vcpu-A gets reset, get the new PC, and is sent on its merry way
- right at the point of entering the guest, we notice that a PC increment is pending (remember the earlier SMC?)
- vcpu-A skips its first instruction...
What could possibly go wrong?
Well, I'm glad you asked. For pKVM as a NV guest, that first instruction is extremely significant, as it indicates whether the CPU is booting or resuming. Having skipped that instruction, nothing makes any sense anymore, and CPU hotplugging fails.
This is all caused by the decoupling of PC update from the handling of an exception that triggers such update, making it non-obvious what affects what when.
Fix this train wreck by discarding all the PC-affecting state on vcpu reset.
--- arch/arm64/kvm/reset.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
arch/arm64/kvm/reset.c +14 -0
@@ -247,6 +247,20 @@ void kvm_reset_vcpu(struct kvm_vcpu *vcpkvm_vcpu_set_be (vcpu); *vcpu_pc (vcpu) = target_pc; + +/* +* We may come from a state where either a PC update was +* pending (SMC call resulting in PC being increpented to +* skip the SMC) or a pending exception. Make sure we get +* rid of all that, as this cannot be valid out of reset. +* +* Note that clearing the exception mask also clears PC +* updates, but that's an implementation detail, and we +* really want to make it explicit. +*/ +vcpu_clear_flag (vcpu,PENDING_EXCEPTION ); +vcpu_clear_flag (vcpu,EXCEPT_MASK ); +vcpu_clear_flag (vcpu,INCREMENT_PC );vcpu_set_reg (vcpu,0 , reset_state.r0); }
Greg Kroah-Hartman
maintainerPATCH 223/342 KVM: arm64: Fix the descriptor address in __kvm_at_swap_desc()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zenghui Yu (Huawei) <[email protected]>
commit 0496acc42fb51eee040b5170cec05cec41385540 upstream.
Using "(u64 __user *)hva + offset" to get the virtual addresses of S1/S2 descriptors looks really wrong, if offset is not zero. What we want to get for swapping is hva + offset, not hva + offset*8. ;-)
Fix it.
--- arch/arm64/kvm/at.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm64/kvm/at.c +1 -1
@@ -1785,7 +1785,7 @@ int __kvm_at_swap_desc(struct kvm *kvm,if (!writable)return -EPERM ; - ptep = (u64 __user *)hva + offset; + ptep = (void __user *)hva + offset;if (cpus_have_final_cap (ARM64_HAS_LSE_ATOMICS )) r =__lse_swap_desc (ptep, old, new);else
Greg Kroah-Hartman
maintainerPATCH 224/342 hwmon: (pmbus/ina233) Fix error handling and sign extension in shunt voltage read
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sanman Pradhan <[email protected]>
commit f7e775c4694782844c66da5316fed82881835cf8 upstream.
ina233_read_word_data() reads MFR_READ_VSHUNT via pmbus_read_word_data() but has two issues:
1. The return value is not checked for errors before being used in arithmetic. A negative error code from a failed I2C transaction is passed directly to DIV_ROUND_CLOSEST(), producing garbage data.
2. MFR_READ_VSHUNT is a 16-bit two's complement value. Negative shunt voltages (values with bit 15 set) are treated as large positive values since pmbus_read_word_data() returns them zero-extended in an int. This leads to incorrect scaling in the VIN coefficient conversion.
Fix both issues by adding an error check, casting to s16 for proper sign extension, and clamping the result to a valid non-negative range. The clamp is necessary because read_word_data callbacks must return non-negative values on success (negative values indicate errors to the pmbus core).
--- drivers/hwmon/pmbus/ina233.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/hwmon/pmbus/ina233.c +2 -1
@@ -72,7 +72,8 @@ static int ina233_read_word_data(struct/* Adjust returned value to match VIN coefficients */ /* VIN: 1.25 mV VSHUNT: 2.5 uV LSB */ - ret =DIV_ROUND_CLOSEST (ret *25 ,12500 ); + ret =clamp_val (DIV_ROUND_CLOSEST ((s16 )ret *25 ,12500 ), +S16_MIN ,S16_MAX ) &0xffff ;break ;default : ret = -ENODATA ;
Greg Kroah-Hartman
maintainerPATCH 225/342 hwmon: (pmbus/isl68137) Add mutex protection for AVS enable sysfs attributes
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sanman Pradhan <[email protected]>
commit 3075a3951f7708da5a8ab47b0b7d068a32f69e58 upstream.
The custom avs0_enable and avs1_enable sysfs attributes access PMBus registers through the exported API helpers (pmbus_read_byte_data, pmbus_read_word_data, pmbus_write_word_data, pmbus_update_byte_data) without holding the PMBus update_lock mutex. These exported helpers do not acquire the mutex internally, unlike the core's internal callers which hold the lock before invoking them.
The store callback is especially vulnerable: it performs a multi-step read-modify-write sequence (read VOUT_COMMAND, write VOUT_COMMAND, then update OPERATION) where concurrent access from another thread could interleave and corrupt the register state.
Add pmbus_lock_interruptible()/pmbus_unlock() around both the show and store callbacks to serialize PMBus register access with the rest of the driver.
--- drivers/hwmon/pmbus/isl68137.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-)
drivers/hwmon/pmbus/isl68137.c +18 -3
@@ -96,7 +96,15 @@ static ssize_t isl68137_avs_enable_show_int page, char *buf) { - int val = pmbus_read_byte_data(client, page, PMBUS_OPERATION); + int val; + + val =pmbus_lock_interruptible (client); +if (val) +return val; + + val =pmbus_read_byte_data (client, page,PMBUS_OPERATION ); + +pmbus_unlock (client);if (val <0 )return val;
@@ -118,6 +126,10 @@ static ssize_t isl68137_avs_enable_store op_val = result ?ISL68137_VOUT_AVS :0 ; + rc =pmbus_lock_interruptible (client); +if (rc) +return rc; +/* * Writes to VOUT setpoint over AVSBus will persist after the VRM is * switched to PMBus control. Switching back to AVSBus control
@@ -129,17 +141,20 @@ static ssize_t isl68137_avs_enable_store rc =pmbus_read_word_data (client, page,0xff ,PMBUS_VOUT_COMMAND );if (rc <0 ) -return rc; + goto unlock; rc =pmbus_write_word_data (client, page,PMBUS_VOUT_COMMAND , rc);if (rc <0 ) -return rc; + goto unlock; } rc =pmbus_update_byte_data (client, page,PMBUS_OPERATION ,ISL68137_VOUT_AVS , op_val); +unlock: +pmbus_unlock (client); +return (rc <0 ) ? rc : count; }
Greg Kroah-Hartman
maintainerPATCH 226/342 hwmon: (peci/cputemp) Fix crit_hyst returning delta instead of absolute temperature
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sanman Pradhan <[email protected]>
commit 0adc752b4f7d82af7bd14f7cad3091b3b5d702ba upstream.
The hwmon sysfs ABI expects tempN_crit_hyst to report the temperature at which the critical condition clears, not the hysteresis delta from the critical limit.
The peci cputemp driver currently returns tjmax - tcontrol for crit_hyst_type, which is the hysteresis margin rather than the corresponding absolute temperature.
Return tcontrol directly, and update the documentation accordingly.
--- Documentation/hwmon/peci-cputemp.rst | 10 ++++++---- drivers/hwmon/peci/cputemp.c | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-)
Documentation/hwmon/peci-cputemp.rst +6 -4
@@ -51,8 +51,9 @@ temp1_max Provides thermal control temp temp1_crit Provides shutdown temperature of the CPU package which is also known as the maximum processor junction temperature, Tjmax or Tprochot. -temp1_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of - the CPU package. +temp1_crit_hyst Provides the hysteresis temperature of the CPU + package. Returns Tcontrol, the temperature at which + the critical condition clears. temp2_label "DTS" temp2_input Provides current temperature of the CPU package scaled
@@ -62,8 +63,9 @@ temp2_max Provides thermal control temp temp2_crit Provides shutdown temperature of the CPU package which is also known as the maximum processor junction temperature, Tjmax or Tprochot. -temp2_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of - the CPU package. +temp2_crit_hyst Provides the hysteresis temperature of the CPU + package. Returns Tcontrol, the temperature at which + the critical condition clears. temp3_label "Tcontrol" temp3_input Provides current Tcontrol temperature of the CPU
drivers/hwmon/peci/cputemp.c +1 -1
@@ -131,7 +131,7 @@ static int get_temp_target(struct peci_c *val = priv->temp.target.tjmax;break ;case crit_hyst_type: - *val = priv->temp.target.tjmax - priv->temp.target.tcontrol; + *val = priv->temp.target.tcontrol;break ;default : ret = -EOPNOTSUPP ;
Greg Kroah-Hartman
maintainerPATCH 227/342 hwmon: (peci/cputemp) Fix off-by-one in cputemp_is_visible()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sanman Pradhan <[email protected]>
commit b0c9d8ae71509f25690d57f2efddebf7f4b12194 upstream.
cputemp_is_visible() validates the channel index against CPUTEMP_CHANNEL_NUMS, but currently uses '>' instead of '>='. As a result, channel == CPUTEMP_CHANNEL_NUMS is not rejected even though valid indices are 0 .. CPUTEMP_CHANNEL_NUMS - 1.
Fix the bounds check by using '>=' so invalid channel indices are rejected before indexing the core bitmap.
--- drivers/hwmon/peci/cputemp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hwmon/peci/cputemp.c +1 -1
@@ -319,7 +319,7 @@ static umode_t cputemp_is_visible(const {const struct peci_cputemp *priv = data; -if (channel >CPUTEMP_CHANNEL_NUMS ) +if (channel >=CPUTEMP_CHANNEL_NUMS )return 0 ;if (channel < channel_core)
Greg Kroah-Hartman
maintainerPATCH 228/342 media: mc, v4l2: serialize REINIT and REQBUFS with req_queue_mutex
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuchan Nam <[email protected]>
commit bef4f4a88b73e4cc550d25f665b8a9952af22773 upstream.
MEDIA_REQUEST_IOC_REINIT can run concurrently with VIDIOC_REQBUFS(0) queue teardown paths. This can race request object cleanup against vb2 queue cancellation and lead to use-after-free reports.
We already serialize request queueing against STREAMON/OFF with req_queue_mutex. Extend that serialization to REQBUFS, and also take the same mutex in media_request_ioctl_reinit() so REINIT is in the same exclusion domain.
This keeps request cleanup and queue cancellation from running in parallel for request-capable devices.
--- drivers/media/mc/mc-request.c | 5 +++++ drivers/media/v4l2-core/v4l2-ioctl.c | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-)
drivers/media/mc/mc-request.c +5 -0
@@ -190,6 +190,8 @@ static long media_request_ioctl_reinit(sstruct media_device *mdev = req->mdev;unsigned long flags; +mutex_lock (&mdev->req_queue_mutex); +spin_lock_irqsave (&req->lock, flags);if (req->state !=MEDIA_REQUEST_STATE_IDLE && req->state !=MEDIA_REQUEST_STATE_COMPLETE ) {
@@ -197,6 +199,7 @@ static long media_request_ioctl_reinit(s"request: %s not in idle or complete state, cannot reinit\n" , req->debug_str);spin_unlock_irqrestore (&req->lock, flags); +mutex_unlock (&mdev->req_queue_mutex);return -EBUSY ; }if (req->access_count) {
@@ -204,6 +207,7 @@ static long media_request_ioctl_reinit(s"request: %s is being accessed, cannot reinit\n" , req->debug_str);spin_unlock_irqrestore (&req->lock, flags); +mutex_unlock (&mdev->req_queue_mutex);return -EBUSY ; } req->state =MEDIA_REQUEST_STATE_CLEANING ;
@@ -214,6 +218,7 @@ static long media_request_ioctl_reinit(sspin_lock_irqsave (&req->lock, flags); req->state =MEDIA_REQUEST_STATE_IDLE ;spin_unlock_irqrestore (&req->lock, flags); +mutex_unlock (&mdev->req_queue_mutex);return 0 ; }
drivers/media/v4l2-core/v4l2-ioctl.c +3 -2
@@ -3081,13 +3081,14 @@ static long __video_do_ioctl(struct file }/* -* We need to serialize streamon/off with queueing new requests. +* We need to serialize streamon/off/reqbufs with queueing new requests. * These ioctls may trigger the cancellation of a streaming * operation, and that should not be mixed with queueing a new * request at the same time. */ if (v4l2_device_supports_requests (vfd->v4l2_dev) && - (cmd ==VIDIOC_STREAMON || cmd ==VIDIOC_STREAMOFF )) { + (cmd ==VIDIOC_STREAMON || cmd ==VIDIOC_STREAMOFF || + cmd ==VIDIOC_REQBUFS )) { req_queue_lock = &vfd->v4l2_dev->mdev->req_queue_mutex;if (mutex_lock_interruptible (req_queue_lock))
Greg Kroah-Hartman
maintainerPATCH 229/342 media: verisilicon: Fix kernel panic due to __initconst misuse
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ming Qian <[email protected]>
commit e8d97c270cb46a2a88739019d0f8547adc7d97da upstream.
Fix a kernel panic when probing the driver as a module:
Unable to handle kernel paging request at virtual address ffffd9c18eb05000 of_find_matching_node_and_match+0x5c/0x1a0 hantro_probe+0x2f4/0x7d0 [hantro_vpu]
The imx8mq_vpu_shared_resources array is referenced by variant structures through their shared_devices field. When built as a module, __initconst causes this data to be freed after module init, but it's later accessed during probe, causing a page fault.
The imx8mq_vpu_shared_resources is referenced from non-init code, so keeping __initconst or __initconst_or_module here is wrong.
Drop the __initconst annotation and let it live in the normal .rodata section.
A bug of __initconst called from regular non-init probe code leading to bugs during probe deferrals or during unbind-bind cycles.
--- drivers/media/platform/verisilicon/imx8m_vpu_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/platform/verisilicon/imx8m_vpu_hw.c +1 -1
@@ -343,7 +343,7 @@ const struct hantro_variant imx8mq_vpu_variant = { .num_regs = ARRAY_SIZE(imx8mq_reg_names) }; -static const struct of_device_id imx8mq_vpu_shared_resources[]__initconst = { +static const struct of_device_id imx8mq_vpu_shared_resources[] = { { .compatible ="nxp,imx8mq-vpu-g1" , }, { .compatible ="nxp,imx8mq-vpu-g2" , }, {/* sentinel */ }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 230/342 xfrm: iptfs: validate inner IPv4 header length in IPTFS payload
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Roshan Kumar <[email protected]>
commit 0d10393d5eac33cbd92f7a41fddca12c41d3cb7e upstream.
Add validation of the inner IPv4 packet tot_len and ihl fields parsed from decrypted IPTFS payloads in __input_process_payload(). A crafted ESP packet containing an inner IPv4 header with tot_len=0 causes an infinite loop: iplen=0 leads to capturelen=min(0, remaining)=0, so the data offset never advances and the while(data < tail) loop never terminates, spinning forever in softirq context.
Reject inner IPv4 packets where tot_len < ihl*4 or ihl*4 < sizeof(struct iphdr), which catches both the tot_len=0 case and malformed ihl values. The normal IP stack performs this validation in ip_rcv_core(), but IPTFS extracts and processes inner packets before they reach that layer.
--- net/xfrm/xfrm_iptfs.c | 5 +++++ 1 file changed, 5 insertions(+)
net/xfrm/xfrm_iptfs.c +5 -0
@@ -997,6 +997,11 @@ static bool __input_process_payload(stru iplen =be16_to_cpu (iph->tot_len); iphlen = iph->ihl <<2 ; +if (iplen < iphlen || iphlen <sizeof (*iph)) { +XFRM_INC_STATS (net, +LINUX_MIB_XFRMINHDRERROR ); + goto done; + } protocol =cpu_to_be16 (ETH_P_IP );XFRM_MODE_SKB_CB (skbseq->root_skb)->tos = iph->tos; }else if (iph->version ==0x6 ) {
Greg Kroah-Hartman
maintainerPATCH 231/342 xfrm: iptfs: only publish mode_data after clone setup
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Moses <[email protected]>
commit d849a2f7309fc0616e79d13b008b0a47e0458b6e upstream.
iptfs_clone_state() stores x->mode_data before allocating the reorder window. If that allocation fails, the code frees the cloned state and returns -ENOMEM, leaving x->mode_data pointing at freed memory.
The xfrm clone unwind later runs destroy_state() through x->mode_data, so the failed clone path tears down IPTFS state that clone_state() already freed.
Keep the cloned IPTFS state private until all allocations succeed so failed clones leave x->mode_data unset. The destroy path already handles a NULL mode_data pointer.
--- net/xfrm/xfrm_iptfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
net/xfrm/xfrm_iptfs.c +3 -3
@@ -2664,9 +2664,6 @@ static int iptfs_clone_state(struct xfrmif (!xtfs)return -ENOMEM ; - x->mode_data = xtfs; - xtfs->x = x; - xtfs->ra_newskb =NULL ;if (xtfs->cfg.reorder_win_size) { xtfs->w_saved = kcalloc(xtfs->cfg.reorder_win_size,
@@ -2677,6 +2674,9 @@ static int iptfs_clone_state(struct xfrm } } + x->mode_data = xtfs; + xtfs->x = x; +return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 232/342 virt: tdx-guest: Fix handling of host controlled quote buffer length
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zubin Mithra <[email protected]>
commit c3fd16c3b98ed726294feab2f94f876290bf7b61 upstream.
Validate host controlled value quote_buf->out_len that determines how many bytes of the quote are copied out to guest userspace. In TDX environments with remote attestation, quotes are not considered private, and can be forwarded to an attestation server.
Catch scenarios where the host specifies a response length larger than the guest's allocation, or otherwise races modifying the response while the guest consumes it.
This prevents contents beyond the pages allocated for quote_buf (up to TSM_REPORT_OUTBLOB_MAX) from being read out to guest userspace, and possibly forwarded in attestation requests.
Recall that some deployments want per-container configs-tsm-report interfaces, so the leak may cross container protection boundaries, not just local root.
--- drivers/virt/coco/tdx-guest/tdx-guest.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
drivers/virt/coco/tdx-guest/tdx-guest.c +10 -2
@@ -169,6 +169,8 @@ static void tdx_mr_deinit(const struct a#define GET_QUOTE_SUCCESS 0#define GET_QUOTE_IN_FLIGHT 0xffffffffffffffff +#define TDX_QUOTE_MAX_LEN (GET_QUOTE_BUF_SIZE - sizeof(struct tdx_quote_buf)) +/* struct tdx_quote_buf: Format of Quote request buffer. * @version: Quote format version, filled by TD. * @status: Status code of Quote request, filled by VMM.
@@ -267,6 +269,7 @@ static int tdx_report_new_locked(structu8 *buf;struct tdx_quote_buf *quote_buf = quote_data;struct tsm_report_desc *desc = &report->desc; +u32 out_len;int ret;u64 err;
@@ -304,12 +307,17 @@ static int tdx_report_new_locked(structreturn ret; } - buf =kvmemdup (quote_buf->data, quote_buf->out_len,GFP_KERNEL ); + out_len =READ_ONCE (quote_buf->out_len); + +if (out_len >TDX_QUOTE_MAX_LEN ) +return -EFBIG ; + + buf =kvmemdup (quote_buf->data, out_len,GFP_KERNEL );if (!buf)return -ENOMEM ; report->outblob = buf; - report->outblob_len = quote_buf->out_len; + report->outblob_len = out_len;/* * TODO: parse the PEM-formatted cert chain out of the quote buffer when
Greg Kroah-Hartman
maintainerPATCH 233/342 virtio_net: Fix UAF on dst_ops when IFF_XMIT_DST_RELEASE is cleared and napi_tx is false
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: xietangxin <[email protected]>
commit ba8bda9a0896746053aa97ac6c3e08168729172c upstream.
A UAF issue occurs when the virtio_net driver is configured with napi_tx=N and the device's IFF_XMIT_DST_RELEASE flag is cleared
(e.g., during the configuration of tc route filter rules).
When IFF_XMIT_DST_RELEASE is removed from the net_device, the network stack expects the driver to hold the reference to skb->dst until the packet is fully transmitted and freed. In virtio_net with napi_tx=N, skbs may remain in the virtio transmit ring for an extended period.
If the network namespace is destroyed while these skbs are still pending, the corresponding dst_ops structure has freed. When a subsequent packet is transmitted, free_old_xmit() is triggered to clean up old skbs. It then calls dst_release() on the skb associated with the stale dst_entry. Since the dst_ops (referenced by the dst_entry) has already been freed, a UAF kernel paging request occurs.
fix it by adds skb_dst_drop(skb) in start_xmit to explicitly release the dst reference before the skb is queued in virtio_net.
Call Trace: Unable to handle kernel paging request at virtual address ffff80007e150000 CPU: 2 UID: 0 PID: 6236 Comm: ping Kdump: loaded Not tainted 7.0.0-rc1+ #6 PREEMPT ... percpu_counter_add_batch+0x3c/0x158 lib/percpu_counter.c:98 (P) dst_release+0xe0/0x110 net/core/dst.c:177 skb_release_head_state+0xe8/0x108 net/core/skbuff.c:1177 sk_skb_reason_drop+0x54/0x2d8 net/core/skbuff.c:1255 dev_kfree_skb_any_reason+0x64/0x78 net/core/dev.c:3469 napi_consume_skb+0x1c4/0x3a0 net/core/skbuff.c:1527 __free_old_xmit+0x164/0x230 drivers/net/virtio_net.c:611 [virtio_net] free_old_xmit drivers/net/virtio_net.c:1081 [virtio_net] start_xmit+0x7c/0x530 drivers/net/virtio_net.c:3329 [virtio_net] ...
Reproduction Steps:
NETDEV="enp3s0"
config_qdisc_route_filter() {
tc qdisc del dev $NETDEV root
tc qdisc add dev $NETDEV root handle 1: prio tc filter add dev $NETDEV parent 1:0 \
protocol ip prio 100 route to 100 flowid 1:1
ip route add 192.168.1.100/32 dev $NETDEV realm 100
}
test_ns() {
ip netns add testns
ip link set $NETDEV netns testns
ip netns exec testns ifconfig $NETDEV 10.0.32.46/24 ip netns exec testns ping -c 1 10.0.32.1
ip netns del testns
}
config_qdisc_route_filter
test_ns
sleep 2test_ns
--- drivers/net/virtio_net.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/virtio_net.c +1 -0
@@ -3355,6 +3355,7 @@ static netdev_tx_t start_xmit(struct sk_/* Don't wait up for transmitted skbs to be freed. */ if (!use_napi) {skb_orphan (skb); +skb_dst_drop (skb);nf_reset_ct (skb); }
Greg Kroah-Hartman
maintainerPATCH 234/342 vfio/pci: Fix double free in dma-buf feature
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Williamson <[email protected]>
commit e98137f0a874ab36d0946de4707aa48cb7137d1c upstream.
The error path through vfio_pci_core_feature_dma_buf() ignores its own advice to only use dma_buf_put() after dma_buf_export(), instead falling through the entire unwind chain. In the unlikely event that we encounter file descriptor exhaustion, this can result in an unbalanced refcount on the vfio device and double free of allocated objects.
Avoid this by moving the "put" directly into the error path and return the errno rather than entering the unwind chain.
--- drivers/vfio/pci/vfio_pci_dmabuf.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
drivers/vfio/pci/vfio_pci_dmabuf.c +2 -3
@@ -302,11 +302,10 @@ int vfio_pci_core_feature_dma_buf(struct*/ ret =dma_buf_fd (priv->dmabuf, get_dma_buf.open_flags);if (ret <0 ) - goto err_dma_buf; +dma_buf_put (priv->dmabuf); +return ret; -err_dma_buf: -dma_buf_put (priv->dmabuf); err_dev_put:vfio_device_put_registration (&vdev->vdev); err_free_phys:
Greg Kroah-Hartman
maintainerPATCH 235/342 erofs: add GFP_NOIO in the bio completion if needed
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiucheng Xu <[email protected]>
commit c23df30915f83e7257c8625b690a1cece94142a0 upstream.
The bio completion path in the process context (e.g. dm-verity) will directly call into decompression rather than trigger another workqueue context for minimal scheduling latencies, which can then call vm_map_ram() with GFP_KERNEL.
Due to insufficient memory, vm_map_ram() may generate memory swapping I/O, which can cause submit_bio_wait to deadlock in some scenarios.
Trimmed down the call stack, as follows:
f2fs_submit_read_io
submit_bio //bio_list is initialized.
mmc_blk_mq_recovery
z_erofs_endio
vm_map_ram
__pte_alloc_kernel
__alloc_pages_direct_reclaim
shrink_folio_list
__swap_writepage
submit_bio_wait //bio_list is non-NULL, hang!!!
Use memalloc_noio_{save,restore}() to wrap up this path.
--- fs/erofs/zdata.c | 3 +++ 1 file changed, 3 insertions(+)
fs/erofs/zdata.c +3 -0
@@ -1459,6 +1459,7 @@ static void z_erofs_decompress_kickoff(s int bios) {struct erofs_sb_info *const sbi =EROFS_SB (io->sb); +int gfp_flag;/* wake up the caller thread for sync decompression */ if (io->sync) {
@@ -1491,7 +1492,9 @@ static void z_erofs_decompress_kickoff(s sbi->opt.sync_decompress =EROFS_SYNC_DECOMPRESS_FORCE_ON ;return ; } + gfp_flag =memalloc_noio_save ();z_erofs_decompressqueue_work (&io->u.work); +memalloc_noio_restore (gfp_flag); } static void z_erofs_fill_bio_vec(struct bio_vec *bvec,
Greg Kroah-Hartman
maintainerPATCH 236/342 alarmtimer: Fix argument order in alarm_timer_forward()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhan Xusheng <[email protected]>
commit 5d16467ae56343b9205caedf85e3a131e0914ad8 upstream.
alarm_timer_forward() passes arguments to alarm_forward() in the wrong order:
alarm_forward(alarm, timr->it_interval, now);
However, alarm_forward() is defined as:
u64 alarm_forward(struct alarm *alarm, ktime_t now, ktime_t interval);
and uses the second argument as the current time:
delta = ktime_sub(now, alarm->node.expires);
Passing the interval as "now" results in incorrect delta computation, which can lead to missed expirations or incorrect overrun accounting.
This issue has been present since the introduction of alarm_timer_forward().
Fix this by swapping the arguments.
--- kernel/time/alarmtimer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/time/alarmtimer.c +1 -1
@@ -540,7 +540,7 @@ static s64 alarm_timer_forward(struct k_ {struct alarm *alarm = &timr->it.alarm.alarmtimer; -return alarm_forward (alarm, timr->it_interval, now); +return alarm_forward (alarm, now, timr->it_interval); }/**
Greg Kroah-Hartman
maintainerPATCH 237/342 mm/huge_memory: fix folio isnt locked in softleaf_to_folio()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jinjiang Tu <[email protected]>
commit 4c5e7f0fcd592801c9cc18f29f80fbee84eb8669 upstream.
On arm64 server, we found folio that get from migration entry isn't locked in softleaf_to_folio(). This issue triggers when mTHP splitting and zap_nonpresent_ptes() races, and the root cause is lack of memory barrier in softleaf_to_folio(). The race is as follows:
CPU0 CPU1
deferred_split_scan() zap_nonpresent_ptes()
lock folio
split_folio()
unmap_folio()
change ptes to migration entries
__split_folio_to_order() softleaf_to_folio()
set flags(including PG_locked) for tail pages folio = pfn_folio(softleaf_to_pfn(entry))
smp_wmb() VM_WARN_ON_ONCE(!folio_test_locked(folio))
prep_compound_page() for tail pages
In __split_folio_to_order(), smp_wmb() guarantees page flags of tail pages are visible before the tail page becomes non-compound. smp_wmb() should be paired with smp_rmb() in softleaf_to_folio(), which is missed. As a result, if zap_nonpresent_ptes() accesses migration entry that stores tail pfn, softleaf_to_folio() may see the updated compound_head of tail page before page->flags.
This issue will trigger VM_WARN_ON_ONCE() in pfn_swap_entry_folio() because of the race between folio split and zap_nonpresent_ptes() leading to a folio incorrectly undergoing modification without a folio lock being held.
This is a BUG_ON() before commit 93976a20345b ("mm: eliminate further swapops predicates"), which in merged in v6.19-rc1.
To fix it, add missing smp_rmb() if the softleaf entry is migration entry in softleaf_to_folio() and softleaf_to_page().
--- include/linux/leafops.h | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-)
include/linux/leafops.h +21 -11
@@ -363,6 +363,23 @@ static inline unsigned long softleaf_to_return swp_offset (entry) &SWP_PFN_MASK ; } +static inline void softleaf_migration_sync (softleaf_t entry, +struct folio *folio) +{ +/* +* Ensure we do not race with split, which might alter tail pages into new +* folios and thus result in observing an unlocked folio. +* This matches the write barrier in __split_folio_to_order(). +*/ +smp_rmb (); + +/* +* Any use of migration entries may only occur while the +* corresponding page is locked +*/ +VM_WARN_ON_ONCE (!folio_test_locked (folio)); +} +/** * softleaf_to_page() - Obtains struct page for PFN encoded within leaf entry. * @entry: Leaf entry, softleaf_has_pfn(@entry) must return true.
@@ -374,11 +391,8 @@ static inline struct page *softleaf_to_pstruct page *page =pfn_to_page (softleaf_to_pfn (entry));VM_WARN_ON_ONCE (!softleaf_has_pfn (entry)); -/* -* Any use of migration entries may only occur while the -* corresponding page is locked -*/ -VM_WARN_ON_ONCE (softleaf_is_migration (entry) && !PageLocked (page)); +if (softleaf_is_migration (entry)) +softleaf_migration_sync (entry,page_folio (page));return page; }
@@ -394,12 +408,8 @@ static inline struct folio *softleaf_to_struct folio *folio =pfn_folio (softleaf_to_pfn (entry));VM_WARN_ON_ONCE (!softleaf_has_pfn (entry)); -/* -* Any use of migration entries may only occur while the -* corresponding folio is locked. -*/ -VM_WARN_ON_ONCE (softleaf_is_migration (entry) && - !folio_test_locked (folio)); +if (softleaf_is_migration (entry)) +softleaf_migration_sync (entry, folio);return folio; }
Greg Kroah-Hartman
maintainerPATCH 238/342 writeback: dont block sync for filesystems with no data integrity guarantees
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joanne Koong <[email protected]>
commit 76f9377cd2ab7a9220c25d33940d9ca20d368172 upstream.
Add a SB_I_NO_DATA_INTEGRITY superblock flag for filesystems that cannot guarantee data persistence on sync (eg fuse). For superblocks with this flag set, sync kicks off writeback of dirty inodes but does not wait for the flusher threads to complete the writeback.
This replaces the per-inode AS_NO_DATA_INTEGRITY mapping flag added in commit f9a49aa302a0 ("fs/writeback: skip AS_NO_DATA_INTEGRITY mappings in wait_sb_inodes()"). The flag belongs at the superblock level because data integrity is a filesystem-wide property, not a per-inode one. Having this flag at the superblock level also allows us to skip having to iterate every dirty inode in wait_sb_inodes() only to skip each inode individually.
Prior to this commit, mappings with no data integrity guarantees skipped waiting on writeback completion but still waited on the flusher threads to finish initiating the writeback. Waiting on the flusher threads is unnecessary. This commit kicks off writeback but does not wait on the flusher threads. This change properly addresses a recent report [1] for a suspend-to-RAM hang seen on fuse-overlayfs that was caused by waiting on the flusher threads to finish:
Workqueue: pm_fs_sync pm_fs_sync_work_fn Call Trace: <TASK> __schedule+0x457/0x1720 schedule+0x27/0xd0 wb_wait_for_completion+0x97/0xe0 sync_inodes_sb+0xf8/0x2e0 __iterate_supers+0xdc/0x160 ksys_sync+0x43/0xb0 pm_fs_sync_work_fn+0x17/0xa0 process_one_work+0x193/0x350 worker_thread+0x1a1/0x310 kthread+0xfc/0x240 ret_from_fork+0x243/0x280 ret_from_fork_asm+0x1a/0x30 </TASK>
On fuse this is problematic because there are paths that may cause the flusher thread to block (eg if systemd freezes the user session cgroups first, which freezes the fuse daemon, before invoking the kernel suspend. The kernel suspend triggers ->write_node() which on fuse issues a synchronous setattr request, which cannot be processed since the daemon is frozen. Or if the daemon is buggy and cannot properly complete writeback, initiating writeback on a dirty folio already under writeback leads to writeback_get_folio() -> folio_prepare_writeback() -> unconditional wait on writeback to finish, which will cause a hang). This commit restores fuse to its prior behavior before tmp folios were removed, where sync was essentially a no-op.
--- fs/fs-writeback.c | 18 ++++++++++++------ fs/fuse/file.c | 4 +--- fs/fuse/inode.c | 1 + include/linux/fs/super_types.h | 1 + include/linux/pagemap.h | 11 ----------- 5 files changed, 15 insertions(+), 20 deletions(-)
fs/fs-writeback.c +12 -6
@@ -2759,13 +2759,8 @@ static void wait_sb_inodes(struct super_* The mapping can appear untagged while still on-list since we * do not have the mapping lock. Skip it here, wb completion * will remove it. -* -* If the mapping does not have data integrity semantics, -* there's no need to wait for the writeout to complete, as the -* mapping cannot guarantee that data is persistently stored. */ -if (!mapping_tagged (mapping,PAGECACHE_TAG_WRITEBACK ) || -mapping_no_data_integrity (mapping)) +if (!mapping_tagged (mapping,PAGECACHE_TAG_WRITEBACK ))continue ;spin_unlock_irq (&sb->s_inode_wblist_lock);
@@ -2900,6 +2895,17 @@ void sync_inodes_sb(struct super_block **/ if (bdi == &noop_backing_dev_info)return ; + +/* +* If the superblock has SB_I_NO_DATA_INTEGRITY set, there's no need to +* wait for the writeout to complete, as the filesystem cannot guarantee +* data persistence on sync. Just kick off writeback and return. +*/ +if (sb->s_iflags &SB_I_NO_DATA_INTEGRITY ) { +wakeup_flusher_threads_bdi (bdi,WB_REASON_SYNC ); +return ; + } +WARN_ON (!rwsem_is_locked (&sb->s_umount));/* protect against inode wb switch, see inode_switch_wbs_work_fn() */
fs/fuse/file.c +1 -3
@@ -3200,10 +3200,8 @@ void fuse_init_file_inode(struct inode * inode->i_fop = &fuse_file_operations; inode->i_data.a_ops = &fuse_file_aops; -if (fc->writeback_cache) { +if (fc->writeback_cache)mapping_set_writeback_may_deadlock_on_reclaim (&inode->i_data); -mapping_set_no_data_integrity (&inode->i_data); - }INIT_LIST_HEAD (&fi->write_files);INIT_LIST_HEAD (&fi->queued_writes);
fs/fuse/inode.c +1 -0
@@ -1709,6 +1709,7 @@ static void fuse_sb_defaults(struct supe sb->s_export_op = &fuse_export_operations; sb->s_iflags |=SB_I_IMA_UNVERIFIABLE_SIGNATURE ; sb->s_iflags |=SB_I_NOIDMAP ; + sb->s_iflags |=SB_I_NO_DATA_INTEGRITY ;if (sb->s_user_ns != &init_user_ns) sb->s_iflags |=SB_I_UNTRUSTED_MOUNTER ; sb->s_flags &= ~(SB_NOSEC |SB_I_VERSION );
include/linux/fs/super_types.h +1 -0
@@ -332,5 +332,6 @@ struct super_block {#define SB_I_NOUMASK 0x00001000/* VFS does not apply umask */ #define SB_I_NOIDMAP 0x00002000/* No idmapped mounts on this superblock */ #define SB_I_ALLOW_HSM 0x00004000/* Allow HSM events on this superblock */ +#define SB_I_NO_DATA_INTEGRITY 0x00008000/* fs cannot guarantee data persistence on sync */ #endif /* _LINUX_FS_SUPER_TYPES_H */
include/linux/pagemap.h +0 -11
@@ -210,7 +210,6 @@ enum mapping_flags {AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM =9 ,AS_KERNEL_FILE =10 ,/* mapping for a fake kernel file that shouldn't account usage to user cgroups */ -AS_NO_DATA_INTEGRITY =11 ,/* no data integrity guarantees */ /* Bits 16-25 are used for FOLIO_ORDER */ AS_FOLIO_ORDER_BITS =5 , AS_FOLIO_ORDER_MIN = 16,
@@ -346,16 +345,6 @@ static inline bool mapping_writeback_mayreturn test_bit (AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM , &mapping->flags); } -static inline void mapping_set_no_data_integrity (struct address_space *mapping) -{ -set_bit (AS_NO_DATA_INTEGRITY , &mapping->flags); -} - -static inline bool mapping_no_data_integrity (const struct address_space *mapping) -{ -return test_bit (AS_NO_DATA_INTEGRITY , &mapping->flags); -} -static inline gfp_t mapping_gfp_mask (const struct address_space *mapping) {return mapping->gfp_mask;
Greg Kroah-Hartman
maintainerPATCH 239/342 x86/cpu: Enable FSGSBASE early in cpu_init_exception_handling()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikunj A Dadhania <[email protected]>
commit 05243d490bb7852a8acca7b5b5658019c7797a52 upstream.
Move FSGSBASE enablement from identify_cpu() to cpu_init_exception_handling() to ensure it is enabled before any exceptions can occur on both boot and secondary CPUs.
== Background ==
Exception entry code (paranoid_entry()) uses ALTERNATIVE patching based on X86_FEATURE_FSGSBASE to decide whether to use RDGSBASE/WRGSBASE instructions or the slower RDMSR/SWAPGS sequence for saving/restoring GSBASE.
On boot CPU, ALTERNATIVE patching happens after enabling FSGSBASE in CR4. When the feature is available, the code is permanently patched to use RDGSBASE/WRGSBASE, which require CR4.FSGSBASE=1 to execute without triggering
== Boot Sequence ==
Boot CPU (with CR pinning enabled):
trap_init()
cpu_init() <- Uses unpatched code (RDMSR/SWAPGS)
x2apic_setup()
...
arch_cpu_finalize_init()
identify_boot_cpu()
identify_cpu()
cr4_set_bits(X86_CR4_FSGSBASE) # Enables the feature # This becomes part of cr4_pinned_bits
...
alternative_instructions() <- Patches code to use RDGSBASE/WRGSBASE
Secondary CPUs (with CR pinning enabled):
start_secondary()
cr4_init() <- Code already patched, CR4.FSGSBASE=1
set implicitly via cr4_pinned_bits
cpu_init() <- exceptions work because FSGSBASE is
already enabled
Secondary CPU (with CR pinning disabled):
start_secondary()
cr4_init() <- Code already patched, CR4.FSGSBASE=0
cpu_init()
x2apic_setup()
rdmsrq(MSR_IA32_APICBASE) <- Triggers #VC in SNP guests
exc_vmm_communication()
paranoid_entry() <- Uses RDGSBASE with CR4.FSGSBASE=0
(patched code)
...
ap_starting()
identify_secondary_cpu()
identify_cpu()
cr4_set_bits(X86_CR4_FSGSBASE) <- Enables the feature, which is
too late
== CR Pinning ==
Currently, for secondary CPUs, CR4.FSGSBASE is set implicitly through
CR-pinning: the boot CPU sets it during identify_cpu(), it becomes part of cr4_pinned_bits, and cr4_init() applies those pinned bits to secondary CPUs. This works but creates an undocumented dependency between cr4_init() and the pinning mechanism.
== Problem ==
Secondary CPUs boot after alternatives have been applied globally. They execute already-patched paranoid_entry() code that uses RDGSBASE/WRGSBASE instructions, which require CR4.FSGSBASE=1. Upcoming changes to CR pinning behavior will break the implicit dependency, causing secondary CPUs to generate #UD.
This issue manifests itself on AMD SEV-SNP guests, where the rdmsrq() in x2apic_setup() triggers a #VC exception early during cpu_init(). The #VC handler (exc_vmm_communication()) executes the patched paranoid_entry() path. Without CR4.FSGSBASE enabled, RDGSBASE instructions trigger #UD.
== Fix ==
Enable FSGSBASE explicitly in cpu_init_exception_handling() before loading exception handlers. This makes the dependency explicit and ensures both boot and secondary CPUs have FSGSBASE enabled before paranoid_entry() executes.
--- arch/x86/kernel/cpu/common.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
arch/x86/kernel/cpu/common.c +12 -6
@@ -2042,12 +2042,6 @@ static void identify_cpu(struct cpuinfo_setup_umip (c);setup_lass (c); -/* Enable FSGSBASE instructions if available. */ -if (cpu_has (c,X86_FEATURE_FSGSBASE )) { -cr4_set_bits (X86_CR4_FSGSBASE ); - elf_hwcap2 |=HWCAP2_FSGSBASE ; - } -/* * The vendor-specific functions might have changed features. * Now we do "generic changes."
@@ -2408,6 +2402,18 @@ void cpu_init_exception_handling(bool bo/* GHCB needs to be setup to handle #VC. */ setup_ghcb (); +/* +* On CPUs with FSGSBASE support, paranoid_entry() uses +* ALTERNATIVE-patched RDGSBASE/WRGSBASE instructions. Secondary CPUs +* boot after alternatives are patched globally, so early exceptions +* execute patched code that depends on FSGSBASE. Enable the feature +* before any exceptions occur. +*/ +if (cpu_feature_enabled (X86_FEATURE_FSGSBASE )) { +cr4_set_bits (X86_CR4_FSGSBASE ); + elf_hwcap2 |=HWCAP2_FSGSBASE ; + } +if (cpu_feature_enabled (X86_FEATURE_FRED )) {/* The boot CPU has enabled FRED during early boot */ if (!boot_cpu)
Greg Kroah-Hartman
maintainerPATCH 240/342 x86/cpu: Remove X86_CR4_FRED from the CR4 pinned bits mask
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Borislav Petkov (AMD) <[email protected]>
commit 411df123c017169922cc767affce76282b8e6c85 upstream.
Commit in Fixes added the FRED CR4 bit to the CR4 pinned bits mask so that whenever something else modifies CR4, that bit remains set. Which in itself is a perfectly fine idea.
However, there's an issue when during boot FRED is initialized: first on the BSP and later on the APs. Thus, there's a window in time when exceptions cannot be handled.
This becomes particularly nasty when running as SEV-{ES,SNP} or TDX guests which, when they manage to trigger exceptions during that short window described above, triple fault due to FRED MSRs not being set up yet.
See Link tag below for a much more detailed explanation of the situation.
So, as a result, the commit in that Link URL tried to address this shortcoming by temporarily disabling CR4 pinning when an AP is not online yet.
However, that is a problem in itself because in this case, an attack on the kernel needs to only modify the online bit - a single bit in RW memory - and then disable CR4 pinning and then disable SM*P, leading to more and worse things to happen to the system.
So, instead, remove the FRED bit from the CR4 pinning mask, thus obviating the need to temporarily disable CR4 pinning.
If someone manages to disable FRED when poking at CR4, then idt_invalidate() would make sure the system would crash'n'burn on the first exception triggered, which is a much better outcome security-wise.
--- arch/x86/kernel/cpu/common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/kernel/cpu/common.c +1 -1
@@ -433,7 +433,7 @@ static __always_inline void setup_lass(s/* These bits should not change their value after CPU init is finished. */ static const unsigned long cr4_pinned_mask =X86_CR4_SMEP |X86_CR4_SMAP |X86_CR4_UMIP | -X86_CR4_FSGSBASE |X86_CR4_CET |X86_CR4_FRED ; +X86_CR4_FSGSBASE |X86_CR4_CET ;static DEFINE_STATIC_KEY_FALSE_RO (cr_pinning);static unsigned long cr4_pinned_bits__ro_after_init ;
Greg Kroah-Hartman
maintainerPATCH 241/342 x86/fred: Fix early boot failures on SEV-ES/SNP guests
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikunj A Dadhania <[email protected]>
commit 3645eb7e3915990a149460c151a00894cb586253 upstream.
FRED-enabled SEV-(ES,SNP) guests fail to boot due to the following issues in the early boot sequence:
* FRED does not have a #VC exception handler in the dispatch logic
* Early FRED #VC exceptions attempt to use uninitialized per-CPU GHCBs instead of boot_ghcb
Add X86_TRAP_VC case to fred_hwexc() with a new exc_vmm_communication() function that provides the unified entry point FRED requires, dispatching to existing user/kernel handlers based on privilege level. The function is already declared via DECLARE_IDTENTRY_VC().
Fix early GHCB access by falling back to boot_ghcb in __sev_{get,put}_ghcb() when per-CPU GHCBs are not yet initialized.
--- arch/x86/coco/sev/noinstr.c | 6 ++++++ arch/x86/entry/entry_fred.c | 14 ++++++++++++++ 2 files changed, 20 insertions(+)
arch/x86/coco/sev/noinstr.c +6 -0
@@ -120,6 +120,9 @@ noinstr struct ghcb *__sev_get_ghcb(struWARN_ON (!irqs_disabled ()); +if (!sev_cfg.ghcbs_initialized) +return boot_ghcb; + data =this_cpu_read (runtime_data); ghcb = &data->ghcb_page;
@@ -163,6 +166,9 @@ noinstr void __sev_put_ghcb(struct ghcb_WARN_ON (!irqs_disabled ()); +if (!sev_cfg.ghcbs_initialized) +return ; + data =this_cpu_read (runtime_data); ghcb = &data->ghcb_page;
arch/x86/entry/entry_fred.c +14 -0
@@ -176,6 +176,16 @@ static noinstr void fred_extint(struct p } } +#ifdef CONFIG_AMD_MEM_ENCRYPT +noinstr void exc_vmm_communication(struct pt_regs *regs, unsigned long error_code) +{ +if (user_mode (regs)) +return user_exc_vmm_communication (regs, error_code); +else +return kernel_exc_vmm_communication (regs, error_code); +} +#endif + static noinstr void fred_hwexc(struct pt_regs *regs, unsigned long error_code) {/* Optimize for #PF. That's the only exception which matters performance wise */
@@ -206,6 +216,10 @@ static noinstr void fred_hwexc(struct pt#ifdef CONFIG_X86_CET case X86_TRAP_CP :return exc_control_protection (regs, error_code);#endif +#ifdef CONFIG_AMD_MEM_ENCRYPT +case X86_TRAP_VC :return exc_vmm_communication (regs, error_code); +#endif +default :return fred_bad_type (regs, error_code); }
Greg Kroah-Hartman
maintainerPATCH 242/342 phy: qcom: qmp-ufs: Fix SM8650 PCS table for Gear 4
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abel Vesa <[email protected]>
commit 81af9e40e2e4e1aa95f09fb34811760be6742c58 upstream.
According to internal documentation, on SM8650, when the PHY is configured in Gear 4, the QPHY_V6_PCS_UFS_PLL_CNTL register needs to have the same value as for Gear 5.
At the moment, there is no board that comes with a UFS 3.x device, so this issue doesn't show up, but with the new Eliza SoC, which uses the same init sequence as SM8650, on the MTP board, the link startup fails with the current Gear 4 PCS table.
So fix that by moving the entry into the PCS generic table instead, while keeping the value from Gear 5 configuration.
--- drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/phy/qualcomm/phy-qcom-qmp-ufs.c +1 -2
@@ -928,6 +928,7 @@ static const struct qmp_phy_init_tbl sm8QMP_PHY_INIT_CFG (QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1 ,0x02 ),QMP_PHY_INIT_CFG (QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1 ,0x43 ),QMP_PHY_INIT_CFG (QPHY_V6_PCS_UFS_PCS_CTRL1 ,0xc1 ), +QMP_PHY_INIT_CFG (QPHY_V6_PCS_UFS_PLL_CNTL ,0x33 ),QMP_PHY_INIT_CFG (QPHY_V6_PCS_UFS_TX_LARGE_AMP_DRV_LVL ,0x0f ),QMP_PHY_INIT_CFG (QPHY_V6_PCS_UFS_RX_SIGDET_CTRL2 ,0x68 ), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S4, 0x0e),
@@ -937,13 +938,11 @@ static const struct qmp_phy_init_tbl sm8 };static const struct qmp_phy_init_tbl sm8650_ufsphy_g4_pcs[] = { -QMP_PHY_INIT_CFG (QPHY_V6_PCS_UFS_PLL_CNTL ,0x13 ),QMP_PHY_INIT_CFG (QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY ,0x04 ),QMP_PHY_INIT_CFG (QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY ,0x04 ), };static const struct qmp_phy_init_tbl sm8650_ufsphy_g5_pcs[] = { -QMP_PHY_INIT_CFG (QPHY_V6_PCS_UFS_PLL_CNTL ,0x33 ),QMP_PHY_INIT_CFG (QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY ,0x05 ),QMP_PHY_INIT_CFG (QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY ,0x05 ),QMP_PHY_INIT_CFG (QPHY_V6_PCS_UFS_RX_HS_G5_SYNC_LENGTH_CAPABILITY ,0x4d ),
Greg Kroah-Hartman
maintainerPATCH 243/342 ovl: make fsync after metadata copy-up opt-in mount option
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fei Lv <[email protected]>
commit 1f6ee9be92f8df85a8c9a5a78c20fd39c0c21a95 upstream.
Commit 7d6899fb69d25 ("ovl: fsync after metadata copy-up") was done to fix durability of overlayfs copy up on an upper filesystem which does not enforce ordering on storing of metadata changes (e.g. ubifs).
In an earlier revision of the regressing commit by Lei Lv, the metadata fsync behavior was opt-in via a new "fsync=strict" mount option. We were hoping that the opt-in mount option could be avoided, so the change was only made to depend on metacopy=off, in the hope of not hurting performance of metadata heavy workloads, which are more likely to be using metacopy=on.
This hope was proven wrong by a performance regression report from Google COS workload after upgrade to kernel 6.12.
This is an adaptation of Lei's original "fsync=strict" mount option to the existing upstream code.
The new mount option is mutually exclusive with the "volatile" mount option, so the latter is now an alias to the "fsync=volatile" mount option.
Depends: 50e638beb67e0 ("ovl: Use str_on_off() helper in ovl_show_options()")
--- Documentation/filesystems/overlayfs.rst | 50 ++++++++++++++++++++++++++++++++ fs/overlayfs/copy_up.c | 6 +-- fs/overlayfs/overlayfs.h | 21 +++++++++++++ fs/overlayfs/ovl_entry.h | 7 ---- fs/overlayfs/params.c | 33 +++++++++++++++++---- fs/overlayfs/super.c | 2 - 6 files changed, 104 insertions(+), 15 deletions(-)
Documentation/filesystems/overlayfs.rst +50 -0
@@ -783,6 +783,56 @@ controlled by the "uuid" mount option, w mounted with "uuid=on". +Durability and copy up +---------------------- + +The fsync(2) system call ensures that the data and metadata of a file +are safely written to the backing storage, which is expected to +guarantee the existence of the information post system crash. + +Without an fsync(2) call, there is no guarantee that the observed +data after a system crash will be either the old or the new data, but +in practice, the observed data after crash is often the old or new data +or a mix of both. + +When an overlayfs file is modified for the first time, copy up will +create a copy of the lower file and its parent directories in the upper +layer. Since the Linux filesystem API does not enforce any particular +ordering on storing changes without explicit fsync(2) calls, in case +of a system crash, the upper file could end up with no data at all +(i.e. zeros), which would be an unusual outcome. To avoid this +experience, overlayfs calls fsync(2) on the upper file before completing +data copy up with rename(2) or link(2) to make the copy up "atomic". + +By default, overlayfs does not explicitly call fsync(2) on copied up +directories or on metadata-only copy up, so it provides no guarantee to +persist the user's modification unless the user calls fsync(2). +The fsync during copy up only guarantees that if a copy up is observed +after a crash, the observed data is not zeroes or intermediate values +from the copy up staging area. + +On traditional local filesystems with a single journal (e.g. ext4, xfs), +fsync on a file also persists the parent directory changes, because they +are usually modified in the same transaction, so metadata durability during +data copy up effectively comes for free. Overlayfs further limits risk by +disallowing network filesystems as upper layer. + +Overlayfs can be tuned to prefer performance or durability when storing +to the underlying upper layer. This is controlled by the "fsync" mount +option, which supports these values: + +- "auto": (default) + Call fsync(2) on upper file before completion of data copy up. + No explicit fsync(2) on directory or metadata-only copy up. +- "strict": + Call fsync(2) on upper file and directories before completion of any + copy up. +- "volatile": [*] + Prefer performance over durability (see `Volatile mount`_) + +[*] The mount option "volatile" is an alias to "fsync=volatile". + + Volatile mount --------------
fs/overlayfs/copy_up.c +3 -3
@@ -1146,15 +1146,15 @@ static int ovl_copy_up_one(struct dentryreturn -EOVERFLOW ;/* -* With metacopy disabled, we fsync after final metadata copyup, for +* With "fsync=strict", we fsync after final metadata copyup, for * both regular files and directories to get atomic copyup semantics * on filesystems that do not use strict metadata ordering (e.g. ubifs). * -* With metacopy enabled we want to avoid fsync on all meta copyup +* By default, we want to avoid fsync on all meta copyup, because * that will hurt performance of workloads such as chown -R, so we * only fsync on data copyup as legacy behavior. */ - ctx.metadata_fsync = !OVL_FS (dentry->d_sb)->config.metacopy && + ctx.metadata_fsync =ovl_should_sync_metadata (OVL_FS (dentry->d_sb)) && (S_ISREG (ctx.stat.mode) ||S_ISDIR (ctx.stat.mode)); ctx.metacopy =ovl_need_meta_copy_up (dentry, ctx.stat.mode, flags);
fs/overlayfs/overlayfs.h +21 -0
@@ -99,6 +99,12 @@ enum { OVL_VERITY_REQUIRE, }; +enum { +OVL_FSYNC_VOLATILE , +OVL_FSYNC_AUTO , +OVL_FSYNC_STRICT , +}; +/* * The tuple (fh,uuid) is a universal unique identifier for a copy up origin, * where:
@@ -656,6 +662,21 @@ static inline bool ovl_xino_warn(structreturn ofs->config.xino ==OVL_XINO_ON ; } +static inline bool ovl_should_sync (struct ovl_fs *ofs) +{ +return ofs->config.fsync_mode !=OVL_FSYNC_VOLATILE ; +} + +static inline bool ovl_should_sync_metadata (struct ovl_fs *ofs) +{ +return ofs->config.fsync_mode ==OVL_FSYNC_STRICT ; +} + +static inline bool ovl_is_volatile (struct ovl_config *config) +{ +return config->fsync_mode ==OVL_FSYNC_VOLATILE ; +} +/* * To avoid regressions in existing setups with overlay lower offline changes, * we allow lower changes only if none of the new features are used.
fs/overlayfs/ovl_entry.h +1 -6
@@ -18,7 +18,7 @@ struct ovl_config {int xino;bool metacopy;bool userxattr; -bool ovl_volatile; +int fsync_mode; };struct ovl_sb {
@@ -120,11 +120,6 @@ static inline struct ovl_fs *OVL_FS(strureturn (struct ovl_fs *)sb->s_fs_info; } -static inline bool ovl_should_sync (struct ovl_fs *ofs) -{ -return !ofs->config.ovl_volatile; -} -static inline unsigned int ovl_numlower (struct ovl_entry *oe) {return oe ? oe->__numlower :0 ;
fs/overlayfs/params.c +28 -5
@@ -58,6 +58,7 @@ enum ovl_opt { Opt_xino, Opt_metacopy, Opt_verity, + Opt_fsync, Opt_volatile, Opt_override_creds, };
@@ -140,6 +141,23 @@ static int ovl_verity_mode_def(void)return OVL_VERITY_OFF ; } +static const struct constant_table ovl_parameter_fsync[] = { + {"volatile" ,OVL_FSYNC_VOLATILE }, + {"auto" ,OVL_FSYNC_AUTO }, + {"strict" ,OVL_FSYNC_STRICT }, + {} +}; + +static const char *ovl_fsync_mode (struct ovl_config *config) +{ +return ovl_parameter_fsync[config->fsync_mode].name; +} + +static int ovl_fsync_mode_def (void ) +{ +return OVL_FSYNC_AUTO ; +} +const struct fs_parameter_spec ovl_parameter_spec[] = {fsparam_string_empty ("lowerdir" , Opt_lowerdir),fsparam_file_or_string ("lowerdir+" , Opt_lowerdir_add),
@@ -155,6 +173,7 @@ const struct fs_parameter_spec ovl_paramfsparam_enum ("xino" , Opt_xino, ovl_parameter_xino),fsparam_enum ("metacopy" , Opt_metacopy, ovl_parameter_bool),fsparam_enum ("verity" , Opt_verity, ovl_parameter_verity), +fsparam_enum ("fsync" , Opt_fsync, ovl_parameter_fsync),fsparam_flag ("volatile" , Opt_volatile), fsparam_flag_no("override_creds", Opt_override_creds), {}
@@ -665,8 +684,11 @@ static int ovl_parse_param(struct fs_concase Opt_verity: config->verity_mode = result.uint_32;break ; +case Opt_fsync: + config->fsync_mode = result.uint_32; +break ;case Opt_volatile: - config->ovl_volatile = true; + config->fsync_mode =OVL_FSYNC_VOLATILE ;break ;case Opt_userxattr: config->userxattr = true;
@@ -800,6 +822,7 @@ int ovl_init_fs_context(struct fs_contex ofs->config.nfs_export = ovl_nfs_export_def; ofs->config.xino =ovl_xino_def (); ofs->config.metacopy = ovl_metacopy_def; + ofs->config.fsync_mode =ovl_fsync_mode_def (); fc->s_fs_info = ofs; fc->fs_private = ctx;
@@ -870,9 +893,9 @@ int ovl_fs_params_verify(const struct ov config->index = false; } -if (!config->upperdir && config->ovl_volatile) { +if (!config->upperdir &&ovl_is_volatile (config)) {pr_info ("option \"volatile\" is meaningless in a non-upper mount, ignoring it.\n" ); - config->ovl_volatile = false; + config->fsync_mode =ovl_fsync_mode_def (); }if (!config->upperdir && config->uuid ==OVL_UUID_ON ) {
@@ -1070,8 +1093,8 @@ int ovl_show_options(struct seq_file *m,seq_printf (m,",xino=%s" ,ovl_xino_mode (&ofs->config));if (ofs->config.metacopy != ovl_metacopy_def)seq_printf (m,",metacopy=%s" ,str_on_off (ofs->config.metacopy)); -if (ofs->config.ovl_volatile) -seq_puts (m,",volatile" ); +if (ofs->config.fsync_mode !=ovl_fsync_mode_def ()) +seq_printf (m,",fsync=%s" ,ovl_fsync_mode (&ofs->config));if (ofs->config.userxattr)seq_puts (m,",userxattr" );if (ofs->config.verity_mode !=ovl_verity_mode_def ())
fs/overlayfs/super.c +1 -1
@@ -776,7 +776,7 @@ static int ovl_make_workdir(struct super* For volatile mount, create a incompat/volatile/dirty file to keep * track of it. */ -if (ofs->config.ovl_volatile) { +if (ovl_is_volatile (&ofs->config)) { err =ovl_create_volatile_dirty (ofs);if (err <0 ) {pr_err ("Failed to create volatile/dirty file.\n" );
Greg Kroah-Hartman
maintainerPATCH 244/342 ovl: fix wrong detection of 32bit inode numbers
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <[email protected]>
commit 53a7c171e9dd833f0a96b545adcb89bd57387239 upstream.
The implicit FILEID_INO32_GEN encoder was changed to be explicit, so we need to fix the detection.
When mounting overlayfs with upperdir and lowerdir on different ext4 filesystems, the expected kmsg log is:
overlayfs: "xino" feature enabled using 32 upper inode bits.
But instead, since the regressing commit, the kmsg log was:
overlayfs: "xino" feature enabled using 2 upper inode bits.
--- fs/overlayfs/util.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
fs/overlayfs/util.c +4 -1
@@ -85,7 +85,10 @@ int ovl_can_decode_fh(struct super_blockif (!exportfs_can_decode_fh (sb->s_export_op))return 0 ; -return sb->s_export_op->encode_fh ?-1 :FILEID_INO32_GEN ; +if (sb->s_export_op->encode_fh == generic_encode_ino32_fh) +return FILEID_INO32_GEN ; + +return -1 ; }struct dentry *ovl_indexdir (struct super_block *sb)
Greg Kroah-Hartman
maintainerPATCH 245/342 scsi: ibmvfc: Fix OOB access in ibmvfc_discover_targets_done()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tyllis Xu <[email protected]>
commit 61d099ac4a7a8fb11ebdb6e2ec8d77f38e77362f upstream.
A malicious or compromised VIO server can return a num_written value in the discover targets MAD response that exceeds max_targets. This value is stored directly in vhost->num_targets without validation, and is then used as the loop bound in ibmvfc_alloc_targets() to index into disc_buf[], which is only allocated for max_targets entries. Indices at or beyond max_targets access kernel memory outside the DMA-coherent allocation. The out-of-bounds data is subsequently embedded in Implicit Logout and PLOGI MADs that are sent back to the VIO server, leaking kernel memory.
Fix by clamping num_written to max_targets before storing it.
--- drivers/scsi/ibmvscsi/ibmvfc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/scsi/ibmvscsi/ibmvfc.c +2 -1
@@ -4965,7 +4965,8 @@ static void ibmvfc_discover_targets_doneswitch (mad_status) {case IBMVFC_MAD_SUCCESS :ibmvfc_dbg (vhost,"Discover Targets succeeded\n" ); - vhost->num_targets =be32_to_cpu (rsp->num_written); + vhost->num_targets =min_t (u32,be32_to_cpu (rsp->num_written), + max_targets);ibmvfc_set_host_action (vhost,IBMVFC_HOST_ACTION_ALLOC_TGTS );break ;case IBMVFC_MAD_FAILED :
Greg Kroah-Hartman
maintainerPATCH 246/342 scsi: ses: Handle positive SCSI error from ses_recv_diag()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Greg Kroah-Hartman <[email protected]>
commit 7a9f448d44127217fabc4065c5ba070d4e0b5d37 upstream.
ses_recv_diag() can return a positive value, which also means that an error happened, so do not only test for negative values.
--- drivers/scsi/ses.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/scsi/ses.c +1 -1
@@ -216,7 +216,7 @@ static unsigned char *ses_get_page2_descunsigned char *type_ptr = ses_dev->page1_types;unsigned char *desc_ptr = ses_dev->page2 +8 ; -if (ses_recv_diag (sdev,2 , ses_dev->page2, ses_dev->page2_len) <0 ) +if (ses_recv_diag (sdev,2 , ses_dev->page2, ses_dev->page2_len))return NULL ;for (i =0 ; i < ses_dev->page1_num_types; i++, type_ptr +=4 ) {
Greg Kroah-Hartman
maintainerPATCH 247/342 net: macb: Move devm_{free,request}_irq() out of spin lock area
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kevin Hao <[email protected]>
commit 317e49358ebbf6390fa439ef3c142f9239dd25fb upstream.
The devm_free_irq() and devm_request_irq() functions should not be executed in an atomic context.
During device suspend, all userspace processes and most kernel threads are frozen. Additionally, we flush all tx/rx status, disable all macb interrupts, and halt rx operations. Therefore, it is safe to split the region protected by bp->lock into two independent sections, allowing devm_free_irq() and devm_request_irq() to run in a non-atomic context. This modification resolves the following lockdep warning:
BUG: sleeping function called from invalid context at kernel/locking/mutex.c:591
in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 501, name: rtcwake
preempt_count: 1, expected: 0
RCU nest depth: 1, expected: 0
7 locks held by rtcwake/501:
#0: ffff0008038c3408 (sb_writers#5){.+.+}-{0:0}, at: vfs_write+0xf8/0x368
#1: ffff0008049a5e88 (&of->mutex#2){+.+.}-{4:4}, at: kernfs_fop_write_iter+0xbc/0x1c8
#2: ffff00080098d588 (kn->active#70){.+.+}-{0:0}, at: kernfs_fop_write_iter+0xcc/0x1c8
#3: ffff800081c84888 (system_transition_mutex){+.+.}-{4:4}, at: pm_suspend+0x1ec/0x290
#4: ffff0008009ba0f8 (&dev->mutex){....}-{4:4}, at: device_suspend+0x118/0x4f0
#5: ffff800081d00458 (rcu_read_lock){....}-{1:3}, at: rcu_lock_acquire+0x4/0x48
#6: ffff0008031fb9e0 (&bp->lock){-.-.}-{3:3}, at: macb_suspend+0x144/0x558
irq event stamp: 8682
hardirqs last enabled at (8681): [<ffff8000813c7d7c>] _raw_spin_unlock_irqrestore+0x44/0x88
hardirqs last disabled at (8682): [<ffff8000813c7b58>] _raw_spin_lock_irqsave+0x38/0x98
softirqs last enabled at (7322): [<ffff8000800f1b4c>] handle_softirqs+0x52c/0x588
softirqs last disabled at (7317): [<ffff800080010310>] __do_softirq+0x20/0x2c
CPU: 1 UID: 0 PID: 501 Comm: rtcwake Not tainted 7.0.0-rc3-next-20260310-yocto-standard+ #125 PREEMPT
Hardware name: ZynqMP ZCU102 Rev1.1 (DT)
Call trace:
show_stack+0x24/0x38 (C)
__dump_stack+0x28/0x38
dump_stack_lvl+0x64/0x88
dump_stack+0x18/0x24
__might_resched+0x200/0x218
__might_sleep+0x38/0x98
__mutex_lock_common+0x7c/0x1378
mutex_lock_nested+0x38/0x50
free_irq+0x68/0x2b0
devm_irq_release+0x24/0x38
devres_release+0x40/0x80
devm_free_irq+0x48/0x88
macb_suspend+0x298/0x558
device_suspend+0x218/0x4f0
dpm_suspend+0x244/0x3a0
dpm_suspend_start+0x50/0x78
suspend_devices_and_enter+0xec/0x560
pm_suspend+0x194/0x290
state_store+0x110/0x158
kobj_attr_store+0x1c/0x30
sysfs_kf_write+0xa8/0xd0
kernfs_fop_write_iter+0x11c/0x1c8
vfs_write+0x248/0x368
ksys_write+0x7c/0xf8
__arm64_sys_write+0x28/0x40
invoke_syscall+0x4c/0xe8
el0_svc_common+0x98/0xf0
do_el0_svc+0x28/0x40
el0_svc+0x54/0x1e0
el0t_64_sync_handler+0x84/0x130
el0t_64_sync+0x198/0x1a0--- drivers/net/ethernet/cadence/macb_main.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
drivers/net/ethernet/cadence/macb_main.c +7 -5
@@ -5832,6 +5832,7 @@ static int __maybe_unused macb_suspend(s/* write IP address into register */ tmp |=MACB_BFEXT (IP ,be32_to_cpu (ifa->ifa_local)); } +spin_unlock_irqrestore (&bp->lock, flags);/* Change interrupt handler and * Enable WoL IRQ on queue 0
@@ -5844,11 +5845,12 @@ static int __maybe_unused macb_suspend(sdev_err (dev,"Unable to request IRQ %d (error %d)\n" , bp->queues[0 ].irq, err); -spin_unlock_irqrestore (&bp->lock, flags);return err; } +spin_lock_irqsave (&bp->lock, flags);queue_writel (bp->queues,IER ,GEM_BIT (WOL ));gem_writel (bp,WOL , tmp); +spin_unlock_irqrestore (&bp->lock, flags); }else { err =devm_request_irq (dev, bp->queues[0 ].irq, macb_wol_interrupt,IRQF_SHARED , netdev->name, bp->queues);
@@ -5856,13 +5858,13 @@ static int __maybe_unused macb_suspend(sdev_err (dev,"Unable to request IRQ %d (error %d)\n" , bp->queues[0 ].irq, err); -spin_unlock_irqrestore (&bp->lock, flags);return err; } +spin_lock_irqsave (&bp->lock, flags);queue_writel (bp->queues,IER ,MACB_BIT (WOL ));macb_writel (bp,WOL , tmp); +spin_unlock_irqrestore (&bp->lock, flags); } -spin_unlock_irqrestore (&bp->lock, flags);enable_irq_wake (bp->queues[0 ].irq); }
@@ -5929,6 +5931,8 @@ static int __maybe_unused macb_resume(stqueue_readl (bp->queues,ISR );if (bp->caps &MACB_CAPS_ISR_CLEAR_ON_WRITE )queue_writel (bp->queues,ISR ,-1 ); +spin_unlock_irqrestore (&bp->lock, flags); +/* Replace interrupt handler on queue 0 */ devm_free_irq (dev, bp->queues[0 ].irq, bp->queues); err = devm_request_irq(dev, bp->queues[0].irq, macb_interrupt,
@@ -5937,10 +5941,8 @@ static int __maybe_unused macb_resume(stdev_err (dev,"Unable to request IRQ %d (error %d)\n" , bp->queues[0 ].irq, err); -spin_unlock_irqrestore (&bp->lock, flags);return err; } -spin_unlock_irqrestore (&bp->lock, flags);disable_irq_wake (bp->queues[0 ].irq);
Greg Kroah-Hartman
maintainerPATCH 248/342 net: macb: Protect access to net_device::ip_ptr with RCU lock
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kevin Hao <[email protected]>
commit baa35a698cea26930679a20a7550bbb4c8319725 upstream.
Access to net_device::ip_ptr and its associated members must be protected by an RCU lock. Since we are modifying this piece of code, let's also move it to execute only when WAKE_ARP is enabled.
To minimize the duration of the RCU lock, a local variable is used to temporarily store the IP address. This change resolves the following
RCU check warning:
WARNING: suspicious RCU usage
7.0.0-rc3-next-20260310-yocto-standard+ #122 Not tainted
-----------------------------
drivers/net/ethernet/cadence/macb_main.c:5944 suspicious rcu_dereference_check() usage!
other info that might help us debug this:
rcu_scheduler_active = 2, debug_locks = 1
5 locks held by rtcwake/518:
#0: ffff000803ab1408 (sb_writers#5){.+.+}-{0:0}, at: vfs_write+0xf8/0x368 #1: ffff0008090bf088 (&of->mutex#2){+.+.}-{4:4}, at: kernfs_fop_write_iter+0xbc/0x1c8 #2: ffff00080098d588 (kn->active#70){.+.+}-{0:0}, at: kernfs_fop_write_iter+0xcc/0x1c8 #3: ffff800081c84888 (system_transition_mutex){+.+.}-{4:4}, at: pm_suspend+0x1ec/0x290 #4: ffff0008009ba0f8 (&dev->mutex){....}-{4:4}, at: device_suspend+0x118/0x4f0
stack backtrace: CPU: 3 UID: 0 PID: 518 Comm: rtcwake Not tainted 7.0.0-rc3-next-20260310-yocto-standard+ #122 PREEMPT Hardware name: ZynqMP ZCU102 Rev1.1 (DT) Call trace: show_stack+0x24/0x38 (C) __dump_stack+0x28/0x38 dump_stack_lvl+0x64/0x88 dump_stack+0x18/0x24 lockdep_rcu_suspicious+0x134/0x1d8 macb_suspend+0xd8/0x4c0 device_suspend+0x218/0x4f0 dpm_suspend+0x244/0x3a0 dpm_suspend_start+0x50/0x78 suspend_devices_and_enter+0xec/0x560 pm_suspend+0x194/0x290 state_store+0x110/0x158 kobj_attr_store+0x1c/0x30 sysfs_kf_write+0xa8/0xd0 kernfs_fop_write_iter+0x11c/0x1c8 vfs_write+0x248/0x368 ksys_write+0x7c/0xf8 __arm64_sys_write+0x28/0x40 invoke_syscall+0x4c/0xe8 el0_svc_common+0x98/0xf0 do_el0_svc+0x28/0x40 el0_svc+0x54/0x1e0 el0t_64_sync_handler+0x84/0x130 el0t_64_sync+0x198/0x1a0
--- drivers/net/ethernet/cadence/macb_main.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-)
drivers/net/ethernet/cadence/macb_main.c +16 -9
@@ -5773,9 +5773,9 @@ static int __maybe_unused macb_suspend(sstruct macb_queue *queue;struct in_device *idev;unsigned long flags; +u32 tmp, ifa_local;unsigned int q;int err; -u32 tmp;if (!device_may_wakeup (&bp->dev->dev))phy_exit (bp->phy);
@@ -5784,14 +5784,21 @@ static int __maybe_unused macb_suspend(sreturn 0 ;if (bp->wol &MACB_WOL_ENABLED ) { -/* Check for IP address in WOL ARP mode */ - idev =__in_dev_get_rcu (bp->dev); -if (idev) - ifa =rcu_dereference (idev->ifa_list); -if ((bp->wolopts &WAKE_ARP ) && !ifa) { -netdev_err (netdev,"IP address not assigned as required by WoL walk ARP\n" ); -return -EOPNOTSUPP ; +if (bp->wolopts &WAKE_ARP ) { +/* Check for IP address in WOL ARP mode */ +rcu_read_lock (); + idev =__in_dev_get_rcu (bp->dev); +if (idev) + ifa =rcu_dereference (idev->ifa_list); +if (!ifa) { +rcu_read_unlock (); +netdev_err (netdev,"IP address not assigned as required by WoL walk ARP\n" ); +return -EOPNOTSUPP ; + } + ifa_local =be32_to_cpu (ifa->ifa_local); +rcu_read_unlock (); } +spin_lock_irqsave (&bp->lock, flags);/* Disable Tx and Rx engines before disabling the queues,
@@ -5830,7 +5837,7 @@ static int __maybe_unused macb_suspend(sif (bp->wolopts &WAKE_ARP ) { tmp |=MACB_BIT (ARP );/* write IP address into register */ - tmp |=MACB_BFEXT (IP ,be32_to_cpu (ifa->ifa_local)); + tmp |=MACB_BFEXT (IP , ifa_local); }spin_unlock_irqrestore (&bp->lock, flags);
Greg Kroah-Hartman
maintainerPATCH 249/342 net: macb: Use dev_consume_skb_any() to free TX SKBs
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kevin Hao <[email protected]>
commit 647b8a2fe474474704110db6bd07f7a139e621eb upstream.
The napi_consume_skb() function is not intended to be called in an IRQ disabled context. However, after commit 6bc8a5098bf4 ("net: macb: Fix tx_ptr_lock locking"), the freeing of TX SKBs is performed with IRQs disabled. To resolve the following call trace, use dev_consume_skb_any() for freeing TX SKBs:
WARNING: kernel/softirq.c:430 at __local_bh_enable_ip+0x174/0x188, CPU#0: ksoftirqd/0/15
Modules linked in:
CPU: 0 UID: 0 PID: 15 Comm: ksoftirqd/0 Not tainted 7.0.0-rc4-next-20260319-yocto-standard-dirty #37 PREEMPT
Hardware name: ZynqMP ZCU102 Rev1.1 (DT)
pstate: 200000c5 (nzCv daIF -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
pc : __local_bh_enable_ip+0x174/0x188
lr : local_bh_enable+0x24/0x38
sp : ffff800082b3bb10
x29: ffff800082b3bb10 x28: ffff0008031f3c00 x27: 000000000011ede0
x26: ffff000800a7ff00 x25: ffff800083937ce8 x24: 0000000000017a80
x23: ffff000803243a78 x22: 0000000000000040 x21: 0000000000000000
x20: ffff000800394c80 x19: 0000000000000200 x18: 0000000000000001
x17: 0000000000000001 x16: ffff000803240000 x15: 0000000000000000
x14: ffffffffffffffff x13: 0000000000000028 x12: ffff000800395650
x11: ffff8000821d1528 x10: ffff800081c2bc08 x9 : ffff800081c1e258
x8 : 0000000100000301 x7 : ffff8000810426ec x6 : 0000000000000000
x5 : 0000000000000001 x4 : 0000000000000001 x3 : 0000000000000000
x2 : 0000000000000008 x1 : 0000000000000200 x0 : ffff8000810428dc
Call trace:
__local_bh_enable_ip+0x174/0x188 (P)
local_bh_enable+0x24/0x38
skb_attempt_defer_free+0x190/0x1d8
napi_consume_skb+0x58/0x108
macb_tx_poll+0x1a4/0x558
__napi_poll+0x50/0x198
net_rx_action+0x1f4/0x3d8
handle_softirqs+0x16c/0x560
run_ksoftirqd+0x44/0x80
smpboot_thread_fn+0x1d8/0x338
kthread+0x120/0x150
ret_from_fork+0x10/0x20
irq event stamp: 29751
hardirqs last enabled at (29750): [<ffff8000813be184>] _raw_spin_unlock_irqrestore+0x44/0x88
hardirqs last disabled at (29751): [<ffff8000813bdf60>] _raw_spin_lock_irqsave+0x38/0x98
softirqs last enabled at (29150): [<ffff8000800f1aec>] handle_softirqs+0x504/0x560
softirqs last disabled at (29153): [<ffff8000800f2fec>] run_ksoftirqd+0x44/0x80--- drivers/net/ethernet/cadence/macb_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/cadence/macb_main.c +1 -1
@@ -1071,7 +1071,7 @@ static void macb_tx_unmap(struct macb *b }if (tx_skb->skb) { -napi_consume_skb (tx_skb->skb, budget); +dev_consume_skb_any (tx_skb->skb); tx_skb->skb =NULL ; } }
Greg Kroah-Hartman
maintainerPATCH 250/342 KVM: x86/mmu: Drop/zap existing present SPTE even when creating an MMIO SPTE
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit aad885e774966e97b675dfe928da164214a71605 upstream.
When installing an emulated MMIO SPTE, do so *after* dropping/zapping the existing SPTE (if it's shadow-present). While commit a54aa15c6bda3 was right about it being impossible to convert a shadow-present SPTE to an MMIO SPTE due to a _guest_ write, it failed to account for writes to guest memory that are outside the scope of KVM.
E.g. if host userspace modifies a shadowed gPTE to switch from a memslot to emulted MMIO and then the guest hits a relevant page fault, KVM will install the MMIO SPTE without first zapping the shadow-present SPTE.
------------[ cut here ]------------ is_shadow_present_pte(*sptep) WARNING: arch/x86/kvm/mmu/mmu.c:484 at mark_mmio_spte+0xb2/0xc0 [kvm], CPU#0: vmx_ept_stale_r/4292 Modules linked in: kvm_intel kvm irqbypass CPU: 0 UID: 1000 PID: 4292 Comm: vmx_ept_stale_r Not tainted 7.0.0-rc2-eafebd2d2ab0-sink-vm #319 PREEMPT Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015 RIP: 0010:mark_mmio_spte+0xb2/0xc0 [kvm] Call Trace: <TASK> mmu_set_spte+0x237/0x440 [kvm] ept_page_fault+0x535/0x7f0 [kvm] kvm_mmu_do_page_fault+0xee/0x1f0 [kvm] kvm_mmu_page_fault+0x8d/0x620 [kvm] vmx_handle_exit+0x18c/0x5a0 [kvm_intel] kvm_arch_vcpu_ioctl_run+0xc55/0x1c20 [kvm] kvm_vcpu_ioctl+0x2d5/0x980 [kvm] __x64_sys_ioctl+0x8a/0xd0 do_syscall_64+0xb5/0x730 entry_SYSCALL_64_after_hwframe+0x4b/0x53 RIP: 0033:0x47fa3f </TASK> ---[ end trace 0000000000000000 ]---
--- arch/x86/kvm/mmu/mmu.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-)
arch/x86/kvm/mmu/mmu.c +8 -6
@@ -3044,12 +3044,6 @@ static int mmu_set_spte(struct kvm_vcpubool prefetch = !fault || fault->prefetch;bool write_fault = fault && fault->write; -if (unlikely (is_noslot_pfn (pfn))) { - vcpu->stat.pf_mmio_spte_created++; -mark_mmio_spte (vcpu, sptep, gfn, pte_access); -return RET_PF_EMULATE ; - } -if (is_shadow_present_pte (*sptep)) {if (prefetch &&is_last_spte (*sptep, level) && pfn ==spte_to_pfn (*sptep))
@@ -3073,6 +3067,14 @@ static int mmu_set_spte(struct kvm_vcpu was_rmapped =1 ; } +if (unlikely (is_noslot_pfn (pfn))) { + vcpu->stat.pf_mmio_spte_created++; +mark_mmio_spte (vcpu, sptep, gfn, pte_access); +if (flush) +kvm_flush_remote_tlbs_gfn (vcpu->kvm, gfn, level); +return RET_PF_EMULATE ; + } + wrprot =make_spte (vcpu, sp, slot, pte_access, gfn, pfn, *sptep, prefetch, false, host_writable, &spte);
Greg Kroah-Hartman
maintainerPATCH 251/342 KVM: x86/mmu: Only WARN in direct MMUs when overwriting shadow-present SPTE
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit df83746075778958954aa0460cca55f4b3fc9c02 upstream.
Adjust KVM's sanity check against overwriting a shadow-present SPTE with a another SPTE with a different target PFN to only apply to direct MMUs, i.e. only to MMUs without shadowed gPTEs. While it's impossible for KVM to overwrite a shadow-present SPTE in response to a guest write, writes from outside the scope of KVM, e.g. from host userspace, aren't detected by KVM's write tracking and so can break KVM's shadow paging rules.
------------[ cut here ]------------ pfn != spte_to_pfn(*sptep) WARNING: arch/x86/kvm/mmu/mmu.c:3069 at mmu_set_spte+0x1e4/0x440 [kvm], CPU#0: vmx_ept_stale_r/872 Modules linked in: kvm_intel kvm irqbypass CPU: 0 UID: 1000 PID: 872 Comm: vmx_ept_stale_r Not tainted 7.0.0-rc2-eafebd2d2ab0-sink-vm #319 PREEMPT Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015 RIP: 0010:mmu_set_spte+0x1e4/0x440 [kvm] Call Trace: <TASK> ept_page_fault+0x535/0x7f0 [kvm] kvm_mmu_do_page_fault+0xee/0x1f0 [kvm] kvm_mmu_page_fault+0x8d/0x620 [kvm] vmx_handle_exit+0x18c/0x5a0 [kvm_intel] kvm_arch_vcpu_ioctl_run+0xc55/0x1c20 [kvm] kvm_vcpu_ioctl+0x2d5/0x980 [kvm] __x64_sys_ioctl+0x8a/0xd0 do_syscall_64+0xb5/0x730 entry_SYSCALL_64_after_hwframe+0x4b/0x53 </TASK> ---[ end trace 0000000000000000 ]---
--- arch/x86/kvm/mmu/mmu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/x86/kvm/mmu/mmu.c +2 -1
@@ -3060,7 +3060,8 @@ static int mmu_set_spte(struct kvm_vcpu child =spte_to_child_sp (pte);drop_parent_pte (vcpu->kvm, child, sptep); flush = true; - }else if (WARN_ON_ONCE (pfn !=spte_to_pfn (*sptep))) { + }else if (pfn !=spte_to_pfn (*sptep)) { +WARN_ON_ONCE (vcpu->arch.mmu->root_role.direct);drop_spte (vcpu->kvm, sptep); flush = true; }else
Greg Kroah-Hartman
maintainerPATCH 252/342 jbd2: gracefully abort on checkpointing state corruptions
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Milos Nikic <[email protected]>
commit bac3190a8e79beff6ed221975e0c9b1b5f2a21da upstream.
This patch targets two internal state machine invariants in checkpoint.c residing inside functions that natively return integer error codes.
- In jbd2_cleanup_journal_tail(): A blocknr of 0 indicates a severely corrupted journal superblock. Replaced the J_ASSERT with a WARN_ON_ONCE and a graceful journal abort, returning -EFSCORRUPTED.
- In jbd2_log_do_checkpoint(): Replaced the J_ASSERT_BH checking for an unexpected buffer_jwrite state. If the warning triggers, we explicitly drop the just-taken get_bh() reference and call __flush_batch() to safely clean up any previously queued buffers in the j_chkpt_bhs array, preventing a memory leak before returning -EFSCORRUPTED.
--- fs/jbd2/checkpoint.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-)
fs/jbd2/checkpoint.c +13 -2
@@ -267,7 +267,15 @@ restart:*/ BUFFER_TRACE (bh,"queue" );get_bh (bh); -J_ASSERT_BH (bh, !buffer_jwrite (bh)); +if (WARN_ON_ONCE (buffer_jwrite (bh))) { +put_bh (bh);/* drop the ref we just took */ +spin_unlock (&journal->j_list_lock); +/* Clean up any previously batched buffers */ +if (batch_count) +__flush_batch (journal, &batch_count); +jbd2_journal_abort (journal, -EFSCORRUPTED ); +return -EFSCORRUPTED ; + } journal->j_chkpt_bhs[batch_count++] = bh; transaction->t_chp_stats.cs_written++; transaction->t_checkpoint_list = jh->b_cpnext;
@@ -325,7 +333,10 @@ int jbd2_cleanup_journal_tail(journal_tif (!jbd2_journal_get_log_tail (journal, &first_tid, &blocknr))return 1 ; -J_ASSERT (blocknr !=0 ); +if (WARN_ON_ONCE (blocknr ==0 )) { +jbd2_journal_abort (journal, -EFSCORRUPTED ); +return -EFSCORRUPTED ; + }/* * We need to make sure that any blocks that were recently written out
Greg Kroah-Hartman
maintainerPATCH 253/342 irqchip/qcom-mpm: Add missing mailbox TX done acknowledgment
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jassi Brar <[email protected]>
commit cfe02147e86307a17057ee4e3604f5f5919571d2 upstream.
The mbox_client for qcom-mpm sends NULL doorbell messages via mbox_send_message() but never signals TX completion.
Set knows_txdone=true and call mbox_client_txdone() after a successful send, matching the pattern used by other Qualcomm mailbox clients (smp2p, smsm, qcom_aoss etc).
--- drivers/irqchip/irq-qcom-mpm.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/irqchip/irq-qcom-mpm.c +3 -0
@@ -306,6 +306,8 @@ static int mpm_pd_power_off(struct generif (ret <0 )return ret; +mbox_client_txdone (priv->mbox_chan,0 ); +return 0 ; }
@@ -434,6 +436,7 @@ static int qcom_mpm_probe(struct platfor } priv->mbox_client.dev = dev; + priv->mbox_client.knows_txdone = true; priv->mbox_chan =mbox_request_channel (&priv->mbox_client,0 );if (IS_ERR (priv->mbox_chan)) { ret =PTR_ERR (priv->mbox_chan);
Greg Kroah-Hartman
maintainerPATCH 254/342 iomap: fix invalid folio access when i_blkbits differs from I/O granularity
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joanne Koong <[email protected]>
commit bd71fb3fea9945987053968f028a948997cba8cc upstream.
Commit aa35dd5cbc06 ("iomap: fix invalid folio access after folio_end_read()") partially addressed invalid folio access for folios without an ifs attached, but it did not handle the case where 1 << inode->i_blkbits matches the folio size but is different from the granularity used for the IO, which means IO can be submitted for less than the full folio for the !ifs case.
In this case, the condition:
if (*bytes_submitted == folio_len)
ctx->cur_folio = NULL;in iomap_read_folio_iter() will not invalidate ctx->cur_folio, and iomap_read_end() will still be called on the folio even though the IO helper owns it and will finish the read on it.
Fix this by unconditionally invalidating ctx->cur_folio for the !ifs case.
--- fs/iomap/buffered-io.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
fs/iomap/buffered-io.c +10 -5
@@ -506,6 +506,7 @@ static int iomap_read_folio_iter(structloff_t length =iomap_length (iter);struct folio *folio = ctx->cur_folio;size_t folio_len =folio_size (folio); +struct iomap_folio_state *ifs;size_t poff, plen;loff_t pos_diff;int ret;
@@ -517,7 +518,7 @@ static int iomap_read_folio_iter(structreturn iomap_iter_advance (iter, length); } -ifs_alloc (iter->inode, folio, iter->flags); + ifs =ifs_alloc (iter->inode, folio, iter->flags); length =min_t (loff_t, length, folio_len -offset_in_folio (folio, pos));while (length) {
@@ -548,11 +549,15 @@ static int iomap_read_folio_iter(struct *bytes_submitted += plen;/* -* If the entire folio has been read in by the IO -* helper, then the helper owns the folio and will end -* the read on it. +* Hand off folio ownership to the IO helper when: +* 1) The entire folio has been submitted for IO, or +* 2) There is no ifs attached to the folio +* +* Case (2) occurs when 1 << i_blkbits matches the folio +* size but the underlying filesystem or block device +* uses a smaller granularity for IO. */ -if (*bytes_submitted == folio_len) +if (*bytes_submitted == folio_len || !ifs) ctx->cur_folio =NULL ; }
Greg Kroah-Hartman
maintainerPATCH 255/342 i2c: designware: amdisp: Fix resume-probe race condition issue
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pratap Nirujogi <[email protected]>
commit e2f1ada8e089dd5a331bcd8b88125ae2af8d188f upstream.
Identified resume-probe race condition in kernel v7.0 with the commit 38fa29b01a6a ("i2c: designware: Combine the init functions"),but this issue existed from the beginning though not detected.
The amdisp i2c device requires ISP to be in power-on state for probe to succeed. To meet this requirement, this device is added to genpd to control ISP power using runtime PM. The pm_runtime_get_sync() called before i2c_dw_probe() triggers PM resume, which powers on ISP and also invokes the amdisp i2c runtime resume before the probe completes resulting in this race condition and a NULL dereferencing issue in v7.0
Fix this race condition by using the genpd APIs directly during probe:
- Call dev_pm_genpd_resume() to Power ON ISP before probe
- Call dev_pm_genpd_suspend() to Power OFF ISP after probe
- Set the device to suspended state with pm_runtime_set_suspended()
- Enable runtime PM only after the device is fully initialized
--- drivers/i2c/busses/i2c-designware-amdisp.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)
drivers/i2c/busses/i2c-designware-amdisp.c +5 -6
@@ -7,6 +7,7 @@#include <linux/module.h> #include <linux/platform_device.h> +#include <linux/pm_domain.h> #include <linux/pm_runtime.h> #include <linux/soc/amd/isp4_misc.h>
@@ -82,22 +83,20 @@ static int amd_isp_dw_i2c_plat_probe(strif (isp_i2c_dev->shared_with_punit)pm_runtime_get_noresume (&pdev->dev); -pm_runtime_enable (&pdev->dev); -pm_runtime_get_sync (&pdev->dev); - +dev_pm_genpd_resume (&pdev->dev); ret =i2c_dw_probe (isp_i2c_dev);if (ret) {dev_err_probe (&pdev->dev, ret,"i2c_dw_probe failed\n" ); goto error_release_rpm; } - -pm_runtime_put_sync (&pdev->dev); +dev_pm_genpd_suspend (&pdev->dev); +pm_runtime_set_suspended (&pdev->dev); +pm_runtime_enable (&pdev->dev);return 0 ; error_release_rpm:amd_isp_dw_i2c_plat_pm_cleanup (isp_i2c_dev); -pm_runtime_put_sync (&pdev->dev);return ret; }
Greg Kroah-Hartman
maintainerPATCH 256/342 futex: Clear stale exiting pointer in futex_lock_pi() retry path
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Davidlohr Bueso <[email protected]>
commit 210d36d892de5195e6766c45519dfb1e65f3eb83 upstream.
Fuzzying/stressing futexes triggered:
WARNING: kernel/futex/core.c:825 at wait_for_owner_exiting+0x7a/0x80, CPU#11: futex_lock_pi_s/524
When futex_lock_pi_atomic() sees the owner is exiting, it returns -EBUSY and stores a refcounted task pointer in 'exiting'.
After wait_for_owner_exiting() consumes that reference, the local pointer is never reset to nil. Upon a retry, if futex_lock_pi_atomic() returns a different error, the bogus pointer is passed to wait_for_owner_exiting().
CPU0 CPU1 CPU2
futex_lock_pi(uaddr)
// acquires the PI futex
exit()
futex_cleanup_begin()
futex_state = EXITING;
futex_lock_pi(uaddr)
futex_lock_pi_atomic()
attach_to_pi_owner()
// observes EXITING
*exiting = owner; // takes ref
return -EBUSY
wait_for_owner_exiting(-EBUSY, owner)
put_task_struct(); // drops ref
// exiting still points to owner
goto retry;
futex_lock_pi_atomic()
lock_pi_update_atomic()
cmpxchg(uaddr)
*uaddr ^= WAITERS // whatever
// value changed
return -EAGAIN;
wait_for_owner_exiting(-EAGAIN, exiting) // stale
WARN_ON_ONCE(exiting)Fix this by resetting upon retry, essentially aligning it with requeue_pi.
--- kernel/futex/pi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/futex/pi.c +2 -1
@@ -918,7 +918,7 @@ int fixup_pi_owner(u32 __user *uaddr, stint futex_lock_pi (u32 __user *uaddr,unsigned int flags,ktime_t *time,int trylock) {struct hrtimer_sleeper timeout, *to; -struct task_struct *exiting =NULL ; +struct task_struct *exiting;struct rt_mutex_waiter rt_waiter;struct futex_q q = futex_q_init;DEFINE_WAKE_Q (wake_q);
@@ -933,6 +933,7 @@ int futex_lock_pi(u32 __user *uaddr, uns to =futex_setup_timer (time, &timeout, flags,0 ); retry: + exiting =NULL ; ret =get_futex_key (uaddr, flags, &q.key,FUTEX_WRITE );if (unlikely (ret !=0 )) goto out;
Greg Kroah-Hartman
maintainerPATCH 257/342 i2c: imx: fix i2c issue when reading multiple messages
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stefan Eichenberger <[email protected]>
commit f88e2e748a1fc3cb4b8d163a9be790812f578850 upstream.
When reading multiple messages, meaning a repeated start is required, polling the bus busy bit must be avoided. This must only be done for the last message. Otherwise, the driver will timeout.
Here an example of such a sequence that fails with an error:
i2ctransfer -y -a 0 w1@0x00 0x02 r1 w1@0x00 0x02 r1
Error: Sending messages failed: Connection timed out
--- drivers/i2c/busses/i2c-imx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/i2c/busses/i2c-imx.c +1 -1
@@ -1522,7 +1522,7 @@ static int i2c_imx_read(struct imx_i2c_sdev_err (&i2c_imx->adapter.dev,"<%s> read timedout\n" , __func__);return -ETIMEDOUT ; } -if (!i2c_imx->stopped) +if (i2c_imx->is_lastmsg && !i2c_imx->stopped)return i2c_imx_bus_busy (i2c_imx,0 , false);return 0 ;
Greg Kroah-Hartman
maintainerPATCH 258/342 i2c: imx: ensure no clock is generated after last read
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stefan Eichenberger <[email protected]>
commit 13101db735bdb29c5f60e95fb578690bd178b30f upstream.
When reading from the I2DR register, right after releasing the bus by clearing MSTA and MTX, the I2C controller might still generate an additional clock cycle which can cause devices to misbehave. Ensure to only read from I2DR after the bus is not busy anymore. Because this requires polling, the read of the last byte is moved outside of the interrupt handler.
An example for such a failing transfer is this:
i2ctransfer -y -a 0 w1@0x00 0x02 r1
Error: Sending messages failed: Connection timed out
It does not happen with every device because not all devices react to the additional clock cycle.
--- drivers/i2c/busses/i2c-imx.c | 51 ++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 19 deletions(-)
drivers/i2c/busses/i2c-imx.c +32 -19
@@ -1018,8 +1018,9 @@ static inline int i2c_imx_isr_read(strucreturn 0 ; } -static inline void i2c_imx_isr_read_continue (struct imx_i2c_struct *i2c_imx) +static inline enum imx_i2c_state i2c_imx_isr_read_continue (struct imx_i2c_struct *i2c_imx) { +enum imx_i2c_state next_state =IMX_I2C_STATE_READ_CONTINUE ;unsigned int temp;if ((i2c_imx->msg->len -1 ) == i2c_imx->msg_buf_idx) {
@@ -1033,18 +1034,20 @@ static inline void i2c_imx_isr_read_cont i2c_imx->stopped =1 ; temp &= ~(I2CR_MSTA |I2CR_MTX );imx_i2c_write_reg (temp, i2c_imx,IMX_I2C_I2CR ); - }else { -/* -* For i2c master receiver repeat restart operation like: -* read -> repeat MSTA -> read/write -* The controller must set MTX before read the last byte in -* the first read operation, otherwise the first read cost -* one extra clock cycle. -*/ - temp =imx_i2c_read_reg (i2c_imx,IMX_I2C_I2CR ); - temp |=I2CR_MTX ; -imx_i2c_write_reg (temp, i2c_imx,IMX_I2C_I2CR ); + +return IMX_I2C_STATE_DONE ; } +/* +* For i2c master receiver repeat restart operation like: +* read -> repeat MSTA -> read/write +* The controller must set MTX before read the last byte in +* the first read operation, otherwise the first read cost +* one extra clock cycle. +*/ + temp =imx_i2c_read_reg (i2c_imx,IMX_I2C_I2CR ); + temp |=I2CR_MTX ; +imx_i2c_write_reg (temp, i2c_imx,IMX_I2C_I2CR ); + next_state =IMX_I2C_STATE_DONE ; }else if (i2c_imx->msg_buf_idx == (i2c_imx->msg->len -2 )) { temp =imx_i2c_read_reg (i2c_imx,IMX_I2C_I2CR ); temp |=I2CR_TXAK ;
@@ -1052,6 +1055,7 @@ static inline void i2c_imx_isr_read_cont } i2c_imx->msg->buf[i2c_imx->msg_buf_idx++] =imx_i2c_read_reg (i2c_imx,IMX_I2C_I2DR ); +return next_state; }static inline void i2c_imx_isr_read_block_data_len (struct imx_i2c_struct *i2c_imx)
@@ -1088,11 +1092,9 @@ static irqreturn_t i2c_imx_master_isr(stbreak ;case IMX_I2C_STATE_READ_CONTINUE : -i2c_imx_isr_read_continue (i2c_imx); -if (i2c_imx->msg_buf_idx == i2c_imx->msg->len) { - i2c_imx->state =IMX_I2C_STATE_DONE ; + i2c_imx->state =i2c_imx_isr_read_continue (i2c_imx); +if (i2c_imx->state ==IMX_I2C_STATE_DONE )wake_up (&i2c_imx->queue); - }break ;case IMX_I2C_STATE_READ_BLOCK_DATA :
@@ -1490,6 +1492,7 @@ static int i2c_imx_read(struct imx_i2c_s bool is_lastmsg) {int block_data = msgs->flags &I2C_M_RECV_LEN ; +int ret =0 ; dev_dbg(&i2c_imx->adapter.dev, "<%s> write slave address: addr=0x%x\n",
@@ -1522,10 +1525,20 @@ static int i2c_imx_read(struct imx_i2c_sdev_err (&i2c_imx->adapter.dev,"<%s> read timedout\n" , __func__);return -ETIMEDOUT ; } -if (i2c_imx->is_lastmsg && !i2c_imx->stopped) -return i2c_imx_bus_busy (i2c_imx,0 , false); +if (i2c_imx->is_lastmsg) { +if (!i2c_imx->stopped) + ret =i2c_imx_bus_busy (i2c_imx,0 , false); +/* +* Only read the last byte of the last message after the bus is +* not busy. Else the controller generates another clock which +* might confuse devices. +*/ +if (!ret) + i2c_imx->msg->buf[i2c_imx->msg_buf_idx++] =imx_i2c_read_reg (i2c_imx, +IMX_I2C_I2DR ); + } -return 0 ; +return ret; } static int i2c_imx_xfer_common(struct i2c_adapter *adapter,
Greg Kroah-Hartman
maintainerPATCH 259/342 dmaengine: fsl-edma: fix channel parameter config for fixed channel requests
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joy Zou <[email protected]>
commit 2e7b5cf72e51c9cf9c8b75190189c757df31ddd9 upstream.
Configure only the requested channel when a fixed channel is specified to avoid modifying other channels unintentionally.
Fix parameter configuration when a fixed DMA channel is requested on i.MX9 AON domain and i.MX8QM/QXP/DXL platforms. When a client requests a fixed channel (e.g., channel 6), the driver traverses channels 0-5 and may unintentionally modify their configuration if they are unused.
This leads to issues such as setting the is_multi_fifo flag unexpectedly, causing memcpy tests to fail when using the dmatest tool.
Only affect edma memcpy test when the channel is fixed.
--- drivers/dma/fsl-edma-main.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-)
drivers/dma/fsl-edma-main.c +11 -15
@@ -317,10 +317,8 @@ static struct dma_chan *fsl_edma3_xlate(return NULL ; i = fsl_chan - fsl_edma->chans; - fsl_chan->priority = dma_spec->args[1 ]; - fsl_chan->is_rxchan = dma_spec->args[2 ] &FSL_EDMA_RX ; - fsl_chan->is_remote = dma_spec->args[2 ] &FSL_EDMA_REMOTE ; - fsl_chan->is_multi_fifo = dma_spec->args[2 ] &FSL_EDMA_MULTI_FIFO ; +if (!b_chmux && i != dma_spec->args[0 ]) +continue ;if ((dma_spec->args[2 ] &FSL_EDMA_EVEN_CH ) && (i &0x1 ))continue ;
@@ -328,17 +326,15 @@ static struct dma_chan *fsl_edma3_xlate(if ((dma_spec->args[2 ] &FSL_EDMA_ODD_CH ) && !(i &0x1 ))continue ; -if (!b_chmux && i == dma_spec->args[0 ]) { - chan =dma_get_slave_channel (chan); - chan->device->privatecnt++; -return chan; - }else if (b_chmux && !fsl_chan->srcid) { -/* if controller support channel mux, choose a free channel */ - chan =dma_get_slave_channel (chan); - chan->device->privatecnt++; - fsl_chan->srcid = dma_spec->args[0 ]; -return chan; - } + fsl_chan->srcid = dma_spec->args[0 ]; + fsl_chan->priority = dma_spec->args[1 ]; + fsl_chan->is_rxchan = dma_spec->args[2 ] &FSL_EDMA_RX ; + fsl_chan->is_remote = dma_spec->args[2 ] &FSL_EDMA_REMOTE ; + fsl_chan->is_multi_fifo = dma_spec->args[2 ] &FSL_EDMA_MULTI_FIFO ; + + chan =dma_get_slave_channel (chan); + chan->device->privatecnt++; +return chan; }return NULL ; }
Greg Kroah-Hartman
maintainerPATCH 260/342 dmaengine: sh: rz-dmac: Protect the driver specific lists
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Claudiu Beznea <[email protected]>
commit abb863e6213dc41a58ef8bb3289b7e77460dabf3 upstream.
The driver lists (ld_free, ld_queue) are used in rz_dmac_free_chan_resources(), rz_dmac_terminate_all(), rz_dmac_issue_pending(), and rz_dmac_irq_handler_thread(), all under the virtual channel lock. Take the same lock in rz_dmac_prep_slave_sg() and rz_dmac_prep_dma_memcpy() as well to avoid concurrency issues, since these functions also check whether the lists are empty and update or remove list entries.
--- drivers/dma/sh/rz-dmac.c | 63 ++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 28 deletions(-)
drivers/dma/sh/rz-dmac.c +35 -28
@@ -10,6 +10,7 @@*/ #include <linux/bitfield.h> +#include <linux/cleanup.h> #include <linux/dma-mapping.h> #include <linux/dmaengine.h> #include <linux/interrupt.h>
@@ -448,6 +449,7 @@ static int rz_dmac_alloc_chan_resources(if (!desc)break ; +/* No need to lock. This is called only for the 1st client. */ list_add_tail (&desc->node, &channel->ld_free); channel->descs_allocated++; }
@@ -503,18 +505,21 @@ rz_dmac_prep_dma_memcpy(struct dma_chandev_dbg (dmac->dev,"%s channel: %d src=0x%pad dst=0x%pad len=%zu\n" , __func__, channel->index, &src, &dest, len); -if (list_empty (&channel->ld_free)) -return NULL ; + scoped_guard(spinlock_irqsave, &channel->vc.lock) { +if (list_empty (&channel->ld_free)) +return NULL ; + + desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node); + + desc->type =RZ_DMAC_DESC_MEMCPY ; + desc->src = src; + desc->dest = dest; + desc->len = len; + desc->direction =DMA_MEM_TO_MEM ; - desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node); - - desc->type =RZ_DMAC_DESC_MEMCPY ; - desc->src = src; - desc->dest = dest; - desc->len = len; - desc->direction =DMA_MEM_TO_MEM ; +list_move_tail (channel->ld_free.next, &channel->ld_queue); + } -list_move_tail (channel->ld_free.next, &channel->ld_queue);return vchan_tx_prep (&channel->vc, &desc->vd, flags); }
@@ -530,27 +535,29 @@ rz_dmac_prep_slave_sg(struct dma_chan *cint dma_length =0 ;int i =0 ; -if (list_empty (&channel->ld_free)) -return NULL ; - - desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node); + scoped_guard(spinlock_irqsave, &channel->vc.lock) { +if (list_empty (&channel->ld_free)) +return NULL ; + + desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node); + +for_each_sg (sgl, sg, sg_len, i) + dma_length +=sg_dma_len (sg); + + desc->type =RZ_DMAC_DESC_SLAVE_SG ; + desc->sg = sgl; + desc->sgcount = sg_len; + desc->len = dma_length; + desc->direction = direction; + +if (direction ==DMA_DEV_TO_MEM ) + desc->src = channel->src_per_address; +else + desc->dest = channel->dst_per_address; -for_each_sg (sgl, sg, sg_len, i) { - dma_length +=sg_dma_len (sg); +list_move_tail (channel->ld_free.next, &channel->ld_queue); } - desc->type =RZ_DMAC_DESC_SLAVE_SG ; - desc->sg = sgl; - desc->sgcount = sg_len; - desc->len = dma_length; - desc->direction = direction; - -if (direction ==DMA_DEV_TO_MEM ) - desc->src = channel->src_per_address; -else - desc->dest = channel->dst_per_address; - -list_move_tail (channel->ld_free.next, &channel->ld_queue);return vchan_tx_prep (&channel->vc, &desc->vd, flags); }
Greg Kroah-Hartman
maintainerPATCH 261/342 dmaengine: sh: rz-dmac: Move CHCTRL updates under spinlock
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Claudiu Beznea <[email protected]>
commit 89a8567d84bde88cb7cdbbac2ab2299c4f991490 upstream.
Both rz_dmac_disable_hw() and rz_dmac_irq_handle_channel() update the CHCTRL register. To avoid concurrency issues when configuring functionalities exposed by this registers, take the virtual channel lock. All other CHCTRL updates were already protected by the same lock.
Previously, rz_dmac_disable_hw() disabled and re-enabled local IRQs, before accessing CHCTRL registers but this does not ensure race-free access. Remove the local IRQ disable/enable code as well.
--- drivers/dma/sh/rz-dmac.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
drivers/dma/sh/rz-dmac.c +4 -5
@@ -298,13 +298,10 @@ static void rz_dmac_disable_hw(struct rz {struct dma_chan *chan = &channel->vc.chan;struct rz_dmac *dmac =to_rz_dmac (chan->device); -unsigned long flags;dev_dbg (dmac->dev,"%s channel %d\n" , __func__, channel->index); -local_irq_save (flags);rz_dmac_ch_writel (channel,CHCTRL_DEFAULT ,CHCTRL ,1 ); -local_irq_restore (flags); }static void rz_dmac_set_dmars_register (struct rz_dmac *dmac,int nr,u32 dmars)
@@ -569,8 +566,8 @@ static int rz_dmac_terminate_all(structunsigned int i;LIST_HEAD (head); -rz_dmac_disable_hw (channel);spin_lock_irqsave (&channel->vc.lock, flags); +rz_dmac_disable_hw (channel);for (i =0 ; i <DMAC_NR_LMDESC ; i++) lmdesc[i].header =0 ;
@@ -707,7 +704,9 @@ static void rz_dmac_irq_handle_channel(sif (chstat &CHSTAT_ER ) {dev_err (dmac->dev,"DMAC err CHSTAT_%d = %08X\n" , channel->index, chstat); -rz_dmac_ch_writel (channel,CHCTRL_DEFAULT ,CHCTRL ,1 ); + + scoped_guard(spinlock_irqsave, &channel->vc.lock) +rz_dmac_ch_writel (channel,CHCTRL_DEFAULT ,CHCTRL ,1 ); goto done; }
Greg Kroah-Hartman
maintainerPATCH 262/342 drm/amdgpu: prevent immediate PASID reuse case
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Huang <[email protected]>
commit 14b81abe7bdc25f8097906fc2f91276ffedb2d26 upstream.
PASID resue could cause interrupt issue when process immediately runs into hw state left by previous process exited with the same PASID, it's possible that page faults are still pending in the IH ring buffer when the process exits and frees up its PASID. To prevent the case, it uses idr cyclic allocator same as kernel pid's.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c | 45 ++++++++++++++++++++++---------- drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h | 1 drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 1 3 files changed, 34 insertions(+), 13 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c +32 -13
@@ -35,10 +35,13 @@* PASIDs are global address space identifiers that can be shared * between the GPU, an IOMMU and the driver. VMs on different devices * may use the same PASID if they share the same address -* space. Therefore PASIDs are allocated using a global IDA. VMs are -* looked up from the PASID per amdgpu_device. +* space. Therefore PASIDs are allocated using IDR cyclic allocator +* (similar to kernel PID allocation) which naturally delays reuse. +* VMs are looked up from the PASID per amdgpu_device. */ -static DEFINE_IDA (amdgpu_pasid_ida); + +static DEFINE_IDR (amdgpu_pasid_idr); +static DEFINE_SPINLOCK (amdgpu_pasid_idr_lock);/* Helper to free pasid from a fence callback */ struct amdgpu_pasid_cb {
@@ -50,8 +53,8 @@ struct amdgpu_pasid_cb {* amdgpu_pasid_alloc - Allocate a PASID * @bits: Maximum width of the PASID in bits, must be at least 1 * -* Allocates a PASID of the given width while keeping smaller PASIDs -* available if possible. +* Uses kernel's IDR cyclic allocator (same as PID allocation). +* Allocates sequentially with automatic wrap-around. * * Returns a positive integer on success. Returns %-EINVAL if bits==0. * Returns %-ENOSPC if no PASID was available. Returns %-ENOMEM on
@@ -59,14 +62,15 @@ struct amdgpu_pasid_cb {*/ int amdgpu_pasid_alloc (unsigned int bits) { -int pasid = -EINVAL ; +int pasid; -for (bits =min (bits,31U ); bits >0 ; bits--) { - pasid =ida_alloc_range (&amdgpu_pasid_ida,1U << (bits -1 ), - (1U << bits) -1 ,GFP_KERNEL ); -if (pasid != -ENOSPC ) -break ; - } +if (bits ==0 ) +return -EINVAL ; + +spin_lock (&amdgpu_pasid_idr_lock); + pasid =idr_alloc_cyclic (&amdgpu_pasid_idr,NULL ,1 , +1U << bits,GFP_KERNEL ); +spin_unlock (&amdgpu_pasid_idr_lock);if (pasid >=0 )trace_amdgpu_pasid_allocated (pasid);
@@ -81,7 +85,10 @@ int amdgpu_pasid_alloc(unsigned int bitsvoid amdgpu_pasid_free (u32 pasid) {trace_amdgpu_pasid_freed (pasid); -ida_free (&amdgpu_pasid_ida, pasid); + +spin_lock (&amdgpu_pasid_idr_lock); +idr_remove (&amdgpu_pasid_idr, pasid); +spin_unlock (&amdgpu_pasid_idr_lock); } static void amdgpu_pasid_free_cb(struct dma_fence *fence,
@@ -616,3 +623,15 @@ void amdgpu_vmid_mgr_fini(struct amdgpu_ } } } + +/** +* amdgpu_pasid_mgr_cleanup - cleanup PASID manager +* +* Cleanup the IDR allocator. +*/ +void amdgpu_pasid_mgr_cleanup (void ) +{ +spin_lock (&amdgpu_pasid_idr_lock); +idr_destroy (&amdgpu_pasid_idr); +spin_unlock (&amdgpu_pasid_idr_lock); +}
drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h +1 -0
@@ -74,6 +74,7 @@ int amdgpu_pasid_alloc(unsigned int bitsvoid amdgpu_pasid_free (u32 pasid);void amdgpu_pasid_free_delayed (struct dma_resv *resv,u32 pasid); +void amdgpu_pasid_mgr_cleanup (void );bool amdgpu_vmid_had_gpu_reset (struct amdgpu_device *adev,struct amdgpu_vmid *id);
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +1 -0
@@ -2898,6 +2898,7 @@ void amdgpu_vm_manager_fini(struct amdgpxa_destroy (&adev->vm_manager.pasids);amdgpu_vmid_mgr_fini (adev); +amdgpu_pasid_mgr_cleanup (); }/**
Greg Kroah-Hartman
maintainerPATCH 263/342 drm/amdgpu: fix strsep() corrupting lockup_timeout on multi-GPU (v3)
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruijing Dong <[email protected]>
commit 2d300ebfc411205fa31ba7741c5821d381912381 upstream.
amdgpu_device_get_job_timeout_settings() passes a pointer directly to the global amdgpu_lockup_timeout[] buffer into strsep(). strsep() destructively replaces delimiter characters with '\0' in-place.
On multi-GPU systems, this function is called once per device. When a multi-value setting like "0,0,0,-1" is used, the first GPU's call transforms the global buffer into "0\00\00\0-1". The second GPU then sees only "0" (terminated at the first '\0'), parses a single value, hits the single-value fallthrough (index == 1), and applies timeout=0 to all rings — causing immediate false job timeouts.
Fix this by copying into a stack-local array before calling strsep(), so the global module parameter buffer remains intact across calls. The buffer is AMDGPU_MAX_TIMEOUT_PARAM_LENGTH
(256) bytes, which is safe for the stack.
v2: wrap commit message to 72 columns, add Assisted-by tag.
v3: use stack array with strscpy() instead of kstrdup()/kfree()
to avoid unnecessary heap allocation (Christian).
This patch was developed with assistance from Claude (claude-opus-4-6).
--- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +11 -2
@@ -4361,7 +4361,8 @@ fail:static int amdgpu_device_get_job_timeout_settings (struct amdgpu_device *adev) { -char *input = amdgpu_lockup_timeout; +char buf[AMDGPU_MAX_TIMEOUT_PARAM_LENGTH ]; +char *input = buf;char *timeout_setting =NULL ;int index =0 ;long timeout;
@@ -4371,9 +4372,17 @@ static int amdgpu_device_get_job_timeout adev->gfx_timeout = adev->compute_timeout = adev->sdma_timeout = adev->video_timeout =msecs_to_jiffies (2000 ); -if (!strnlen (input,AMDGPU_MAX_TIMEOUT_PARAM_LENGTH )) +if (!strnlen (amdgpu_lockup_timeout,AMDGPU_MAX_TIMEOUT_PARAM_LENGTH ))return 0 ; +/* +* strsep() destructively modifies its input by replacing delimiters +* with '\0'. Use a stack copy so the global module parameter buffer +* remains intact for multi-GPU systems where this function is called +* once per device. +*/ +strscpy (buf, amdgpu_lockup_timeout,sizeof (buf)); +while ((timeout_setting =strsep (&input,"," )) &&strnlen (timeout_setting,AMDGPU_MAX_TIMEOUT_PARAM_LENGTH )) { ret =kstrtol (timeout_setting,0 , &timeout);
Greg Kroah-Hartman
maintainerPATCH 264/342 drm/amd/display: Fix DCE LVDS handling
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
commit 90d239cc53723c1a3f89ce08eac17bf3a9e9f2d4 upstream.
LVDS does not use an HPD pin so it may be invalid. Handle this case correctly in link encoder creation.
--- drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c | 6 +--- drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.c | 5 ++- drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.c | 5 ++- drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.c | 5 ++- drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c | 14 ++++------ drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c | 6 +--- 6 files changed, 19 insertions(+), 22 deletions(-)
drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c +2 -4
@@ -651,9 +651,6 @@ static struct link_encoder *dce100_link_return &enc110->base; } -if (enc_init_data->hpd_source >=ARRAY_SIZE (link_enc_hpd_regs)) -return NULL ; - link_regs_id =map_transmitter_id_to_phy_instance (enc_init_data->transmitter);
@@ -662,7 +659,8 @@ static struct link_encoder *dce100_link_ &link_enc_feature, &link_enc_regs[link_regs_id], &link_enc_aux_regs[enc_init_data->channel -1 ], - &link_enc_hpd_regs[enc_init_data->hpd_source]); + enc_init_data->hpd_source >=ARRAY_SIZE (link_enc_hpd_regs) ? + NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]);return &enc110->base; }
drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.c +3 -2
@@ -672,7 +672,7 @@ static struct link_encoder *dce110_link_kzalloc (sizeof (struct dce110_link_encoder ),GFP_KERNEL );int link_regs_id; -if (!enc110 || enc_init_data->hpd_source >=ARRAY_SIZE (link_enc_hpd_regs)) +if (!enc110)return NULL ; link_regs_id =
@@ -683,7 +683,8 @@ static struct link_encoder *dce110_link_ &link_enc_feature, &link_enc_regs[link_regs_id], &link_enc_aux_regs[enc_init_data->channel -1 ], - &link_enc_hpd_regs[enc_init_data->hpd_source]); + enc_init_data->hpd_source >=ARRAY_SIZE (link_enc_hpd_regs) ? + NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]);return &enc110->base; }
drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.c +3 -2
@@ -633,7 +633,7 @@ static struct link_encoder *dce112_link_kzalloc (sizeof (struct dce110_link_encoder ),GFP_KERNEL );int link_regs_id; -if (!enc110 || enc_init_data->hpd_source >=ARRAY_SIZE (link_enc_hpd_regs)) +if (!enc110)return NULL ; link_regs_id =
@@ -644,7 +644,8 @@ static struct link_encoder *dce112_link_ &link_enc_feature, &link_enc_regs[link_regs_id], &link_enc_aux_regs[enc_init_data->channel -1 ], - &link_enc_hpd_regs[enc_init_data->hpd_source]); + enc_init_data->hpd_source >=ARRAY_SIZE (link_enc_hpd_regs) ? + NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]);return &enc110->base; }
drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.c +3 -2
@@ -717,7 +717,7 @@ static struct link_encoder *dce120_link_kzalloc (sizeof (struct dce110_link_encoder ),GFP_KERNEL );int link_regs_id; -if (!enc110 || enc_init_data->hpd_source >=ARRAY_SIZE (link_enc_hpd_regs)) +if (!enc110)return NULL ; link_regs_id =
@@ -728,7 +728,8 @@ static struct link_encoder *dce120_link_ &link_enc_feature, &link_enc_regs[link_regs_id], &link_enc_aux_regs[enc_init_data->channel -1 ], - &link_enc_hpd_regs[enc_init_data->hpd_source]); + enc_init_data->hpd_source >=ARRAY_SIZE (link_enc_hpd_regs) ? + NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]);return &enc110->base; }
drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c +6 -8
@@ -747,18 +747,16 @@ static struct link_encoder *dce60_link_ereturn &enc110->base; } -if (enc_init_data->hpd_source >=ARRAY_SIZE (link_enc_hpd_regs)) -return NULL ; - link_regs_id =map_transmitter_id_to_phy_instance (enc_init_data->transmitter);dce60_link_encoder_construct (enc110, - enc_init_data, - &link_enc_feature, - &link_enc_regs[link_regs_id], - &link_enc_aux_regs[enc_init_data->channel -1 ], - &link_enc_hpd_regs[enc_init_data->hpd_source]); + enc_init_data, + &link_enc_feature, + &link_enc_regs[link_regs_id], + &link_enc_aux_regs[enc_init_data->channel -1 ], + enc_init_data->hpd_source >=ARRAY_SIZE (link_enc_hpd_regs) ? +NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]);return &enc110->base; }
drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c +2 -4
@@ -753,9 +753,6 @@ static struct link_encoder *dce80_link_ereturn &enc110->base; } -if (enc_init_data->hpd_source >=ARRAY_SIZE (link_enc_hpd_regs)) -return NULL ; - link_regs_id =map_transmitter_id_to_phy_instance (enc_init_data->transmitter);
@@ -764,7 +761,8 @@ static struct link_encoder *dce80_link_e &link_enc_feature, &link_enc_regs[link_regs_id], &link_enc_aux_regs[enc_init_data->channel -1 ], - &link_enc_hpd_regs[enc_init_data->hpd_source]); + enc_init_data->hpd_source >=ARRAY_SIZE (link_enc_hpd_regs) ? + NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]);return &enc110->base; }
Greg Kroah-Hartman
maintainerPATCH 265/342 drm/amd/display: Fix drm_edid leak in amdgpu_dm
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Hung <[email protected]>
commit 37c2caa167b0b8aca4f74c32404c5288b876a2a3 upstream.
[WHAT]
When a sink is connected, aconnector->drm_edid was overwritten without freeing the previous allocation, causing a memory leak on resume.
[HOW]
Free the previous drm_edid before updating it.
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +2 -1
@@ -3891,8 +3891,9 @@ void amdgpu_dm_update_connector_after_de aconnector->dc_sink = sink;dc_sink_retain (aconnector->dc_sink); +drm_edid_free (aconnector->drm_edid); + aconnector->drm_edid =NULL ;if (sink->dc_edid.length ==0 ) { - aconnector->drm_edid =NULL ;hdmi_cec_unset_edid (aconnector);if (aconnector->dc_link->aux_mode) {drm_dp_cec_unset_edid (&aconnector->dm_dp_aux.aux);
Greg Kroah-Hartman
maintainerPATCH 266/342 drm/amd/display: check if ext_caps is valid in BL setup
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
commit 9da4f9964abcaeb6e19797d5e3b10faad338a786 upstream.
LVDS connectors don't have extended backlight caps so check if the pointer is valid before accessing it.
--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +1 -1
@@ -5406,7 +5406,7 @@ static void setup_backlight_device(struc caps = &dm->backlight_caps[aconnector->bl_idx];/* Only offer ABM property when non-OLED and user didn't turn off by module parameter */ -if (!caps->ext_caps->bits.oled && amdgpu_dm_abm_level <0 ) +if (caps->ext_caps && !caps->ext_caps->bits.oled && amdgpu_dm_abm_level <0 )drm_object_attach_property (&aconnector->base.base, dm->adev->mode_info.abm_level_property,ABM_SYSFS_CONTROL );
Greg Kroah-Hartman
maintainerPATCH 267/342 drm/i915/dp_tunnel: Fix error handling when clearing stream BW in atomic state
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Imre Deak <[email protected]>
commit 77fcf58df15edcf3f5b5421f24814fb72796def9 upstream.
Clearing the DP tunnel stream BW in the atomic state involves getting the tunnel group state, which can fail. Handle the error accordingly.
This fixes at least one issue where drm_dp_tunnel_atomic_set_stream_bw() failed to get the tunnel group state returning -EDEADLK, which wasn't handled. This lead to the ctx->contended warn later in modeset_lock() while taking a WW mutex for another object in the same atomic state, and thus within the same already contended WW context.
Moving intel_crtc_state_alloc() later would avoid freeing saved_state on the error path; this stable patch leaves that simplification for a follow-up.
--- drivers/gpu/drm/i915/display/intel_display.c | 8 +++++++- drivers/gpu/drm/i915/display/intel_dp_tunnel.c | 20 ++++++++++++++------ drivers/gpu/drm/i915/display/intel_dp_tunnel.h | 11 +++++++---- 3 files changed, 28 insertions(+), 11 deletions(-)
drivers/gpu/drm/i915/display/intel_display.c +7 -1
@@ -4578,6 +4578,7 @@ intel_crtc_prepare_cleared_state(structstruct intel_crtc_state *crtc_state =intel_atomic_get_new_crtc_state (state, crtc);struct intel_crtc_state *saved_state; +int err; saved_state =intel_crtc_state_alloc (crtc);if (!saved_state)
@@ -4586,7 +4587,12 @@ intel_crtc_prepare_cleared_state(struct/* free the old crtc_state->hw members */ intel_crtc_free_hw_state (crtc_state); -intel_dp_tunnel_atomic_clear_stream_bw (state, crtc_state); + err =intel_dp_tunnel_atomic_clear_stream_bw (state, crtc_state); +if (err) { +kfree (saved_state); + +return err; + }/* FIXME: before the switch to atomic started, a new pipe_config was * kzalloc'd. Code that depends on any field being zero should be
drivers/gpu/drm/i915/display/intel_dp_tunnel.c +14 -6
@@ -622,19 +622,27 @@ int intel_dp_tunnel_atomic_compute_strea* * Clear any DP tunnel stream BW requirement set by * intel_dp_tunnel_atomic_compute_stream_bw(). +* +* Returns 0 in case of success, a negative error code otherwise. */ -void intel_dp_tunnel_atomic_clear_stream_bw (struct intel_atomic_state *state, -struct intel_crtc_state *crtc_state) +int intel_dp_tunnel_atomic_clear_stream_bw (struct intel_atomic_state *state, +struct intel_crtc_state *crtc_state) {struct intel_crtc *crtc =to_intel_crtc (crtc_state->uapi.crtc); +int err;if (!crtc_state->dp_tunnel_ref.tunnel) -return ; +return 0 ; + + err =drm_dp_tunnel_atomic_set_stream_bw (&state->base, + crtc_state->dp_tunnel_ref.tunnel, + crtc->pipe,0 ); +if (err) +return err; -drm_dp_tunnel_atomic_set_stream_bw (&state->base, - crtc_state->dp_tunnel_ref.tunnel, - crtc->pipe,0 );drm_dp_tunnel_ref_put (&crtc_state->dp_tunnel_ref); + +return 0 ; }/**
drivers/gpu/drm/i915/display/intel_dp_tunnel.h +7 -4
@@ -40,8 +40,8 @@ int intel_dp_tunnel_atomic_compute_streastruct intel_dp *intel_dp, const struct intel_connector *connector, struct intel_crtc_state *crtc_state); -void intel_dp_tunnel_atomic_clear_stream_bw (struct intel_atomic_state *state, -struct intel_crtc_state *crtc_state); +int intel_dp_tunnel_atomic_clear_stream_bw (struct intel_atomic_state *state, +struct intel_crtc_state *crtc_state);int intel_dp_tunnel_atomic_add_state_for_crtc (struct intel_atomic_state *state,struct intel_crtc *crtc);
@@ -88,9 +88,12 @@ intel_dp_tunnel_atomic_compute_stream_bwreturn 0 ; } -static inline void +static inline int intel_dp_tunnel_atomic_clear_stream_bw (struct intel_atomic_state *state, -struct intel_crtc_state *crtc_state) {} +struct intel_crtc_state *crtc_state) +{ +return 0 ; +} static inline int intel_dp_tunnel_atomic_add_state_for_crtc(struct intel_atomic_state *state,
Greg Kroah-Hartman
maintainerPATCH 268/342 drm/i915: Order OP vs. timeout correctly in __wait_for()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ville Syrjälä <[email protected]>
commit 6ad2a661ff0d3d94884947d2a593311ba46d34c2 upstream.
Put the barrier() before the OP so that anything we read out in OP and check in COND will actually be read out after the timeout has been evaluated.
Currently the only place where we use OP is __intel_wait_for_register(), but the use there is precisely susceptible to this reordering, assuming the ktime_*() stuff itself doesn't act as a sufficient barrier:
__intel_wait_for_register(...)
{
...
ret = __wait_for(reg_value = intel_uncore_read_notrace(...),
(reg_value & mask) == value, ...);
...
}--- drivers/gpu/drm/i915/i915_wait_util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/i915/i915_wait_util.h +1 -1
@@ -25,9 +25,9 @@might_sleep (); \for (;;) { \const bool expired__ =ktime_after (ktime_get_raw (), end__); \ -OP ; \/* Guarantee COND check prior to timeout */ \barrier (); \ +OP ; \if (COND ) { \ ret__ =0 ; \break ; \
Greg Kroah-Hartman
maintainerPATCH 269/342 drm/i915: Unlink NV12 planes earlier
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ville Syrjälä <[email protected]>
commit bfa71b7a9dc6b5b8af157686e03308291141d00c upstream.
unlink_nv12_plane() will clobber parts of the plane state potentially already set up by plane_atomic_check(), so we must make sure not to call the two in the wrong order. The problem happens when a plane previously selected as a Y plane is now configured as a normal plane by user space. plane_atomic_check() will first compute the proper plane state based on the userspace request, and unlink_nv12_plane() later clears some of the state.
This used to work on account of unlink_nv12_plane() skipping the state clearing based on the plane visibility. But I removed that check, thinking it was an impossible situation. Now when that situation happens unlink_nv12_plane() will just WARN and proceed to clobber the state.
Rather than reverting to the old way of doing things, I think it's more clear if we unlink the NV12 planes before we even compute the new plane state.
--- drivers/gpu/drm/i915/display/intel_plane.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/gpu/drm/i915/display/intel_plane.c +9 -2
@@ -433,11 +433,16 @@ void intel_plane_copy_hw_state(struct indrm_framebuffer_get (plane_state->hw.fb); } +static void unlink_nv12_plane (struct intel_crtc_state *crtc_state, +struct intel_plane_state *plane_state); +void intel_plane_set_invisible (struct intel_crtc_state *crtc_state,struct intel_plane_state *plane_state) {struct intel_plane *plane =to_intel_plane (plane_state->uapi.plane); +unlink_nv12_plane (crtc_state, plane_state); + crtc_state->active_planes &= ~BIT (plane->id); crtc_state->scaled_planes &= ~BIT (plane->id); crtc_state->nv12_planes &= ~BIT (plane->id);
@@ -1511,6 +1516,9 @@ static void unlink_nv12_plane(struct intstruct intel_display *display =to_intel_display (plane_state);struct intel_plane *plane =to_intel_plane (plane_state->uapi.plane); +if (!plane_state->planar_linked_plane) +return ; + plane_state->planar_linked_plane =NULL ;if (!plane_state->is_y_plane)
@@ -1548,8 +1556,7 @@ static int icl_check_nv12_planes(structif (plane->pipe != crtc->pipe)continue ; -if (plane_state->planar_linked_plane) -unlink_nv12_plane (crtc_state, plane_state); +unlink_nv12_plane (crtc_state, plane_state); }if (!crtc_state->nv12_planes)
Greg Kroah-Hartman
maintainerPATCH 270/342 LoongArch: Fix missing NULL checks for kstrdup()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Li Jun <[email protected]>
commit 3a28daa9b7d7c2ddf2c722e9e95d7e0928bf0cd1 upstream.
1. Replace "of_find_node_by_path("/")" with "of_root" to avoid multiple calls to "of_node_put()".
2. Fix a potential kernel oops during early boot when memory allocation fails while parsing CPU model from device tree.
--- arch/loongarch/kernel/env.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
arch/loongarch/kernel/env.c +3 -4
@@ -42,16 +42,15 @@ static int __init init_cpu_fullname(voidint cpu, ret;char *cpuname;const char *model; -struct device_node *root;/* Parsing cpuname from DTS model property */ - root =of_find_node_by_path ("/" ); - ret =of_property_read_string (root,"model" , &model); + ret =of_property_read_string (of_root,"model" , &model);if (ret ==0 ) { cpuname =kstrdup (model,GFP_KERNEL ); +if (!cpuname) +return -ENOMEM ; loongson_sysconf.cpuname =strsep (&cpuname," " ); } -of_node_put (root);if (loongson_sysconf.cpuname && !strncmp (loongson_sysconf.cpuname,"Loongson" ,8 )) {for (cpu =0 ; cpu <NR_CPUS ; cpu++)
Greg Kroah-Hartman
maintainerPATCH 271/342 LoongArch: vDSO: Emit GNU_EH_FRAME correctly
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xi Ruoyao <[email protected]>
commit e4878c37f6679fdea91b27a0f4e60a871f0b7bad upstream.
With -fno-asynchronous-unwind-tables and --no-eh-frame-hdr (the default of the linker), the GNU_EH_FRAME segment (specified by vdso.lds.S) is empty. This is not valid, as the current DWARF specification mandates the first byte of the EH frame to be the version number 1. It causes some unwinders to complain, for example the ClickHouse query profiler spams the log with messages:
clickhouse-server[365854]: libunwind: unsupported .eh_frame_hdr
version: 127 at 7ffffffb0000
Here "127" is just the byte located at the p_vaddr (0, i.e. the beginning of the vDSO) of the empty GNU_EH_FRAME segment. Cross- checking with /proc/365854/maps has also proven 7ffffffb0000 is the start of vDSO in the process VM image.
In LoongArch the -fno-asynchronous-unwind-tables option seems just a MIPS legacy, and MIPS only uses this option to satisfy the MIPS-specific "genvdso" program, per the commit cfd75c2db17e ("MIPS: VDSO: Explicitly use -fno-asynchronous-unwind-tables"). IIRC it indicates some inherent limitation of the MIPS ELF ABI and has nothing to do with LoongArch. So we can simply flip it over to -fasynchronous-unwind-tables and pass --eh-frame-hdr for linking the vDSO, allowing the profilers to unwind the stack for statistics even if the sample point is taken when the PC is in the vDSO.
However simply adjusting the options above would exploit an issue: when the libgcc unwinder saw the invalid GNU_EH_FRAME segment, it silently falled back to a machine-specific routine to match the code pattern of rt_sigreturn() and extract the registers saved in the sigframe if the code pattern is matched. As unwinding from signal handlers is vital for libgcc to support pthread cancellation etc., the fall-back routine had been silently keeping the LoongArch Linux systems functioning since Linux 5.19. But when we start to emit GNU_EH_FRAME with the correct format, fall-back routine will no longer be used and libgcc will fail to unwind the sigframe, and unwinding from signal handlers will no longer work, causing dozens of glibc test failures. To make it possible to unwind from signal handlers again, it's necessary to code the unwind info in __vdso_rt_sigreturn via .cfi_* directives.
The offsets in the .cfi_* directives depend on the layout of struct sigframe, notably the offset of sigcontext in the sigframe. To use the offset in the assembly file, factor out struct sigframe into a header to allow asm-offsets.c to output the offset for assembly.
To work around a long-term issue in the libgcc unwinder (the pc is unconditionally substracted by 1: doing so is technically incorrect for a signal frame), a nop instruction is included with the two real instructions in __vdso_rt_sigreturn in the same FDE PC range. The same hack has been used on x86 for a long time.
--- arch/loongarch/include/asm/linkage.h | 36 ++++++++++++++++++++++++++++++++++ arch/loongarch/include/asm/sigframe.h | 9 ++++++++ arch/loongarch/kernel/asm-offsets.c | 2 + arch/loongarch/kernel/signal.c | 6 ----- arch/loongarch/vdso/Makefile | 4 +-- arch/loongarch/vdso/sigreturn.S | 6 ++--- 6 files changed, 53 insertions(+), 10 deletions(-) create mode 100644 arch/loongarch/include/asm/sigframe.h
arch/loongarch/include/asm/linkage.h +36 -0
@@ -41,4 +41,40 @@ .cfi_endproc; \SYM_END (name,SYM_T_NONE ) +/* +* This is for the signal handler trampoline, which is used as the return +* address of the signal handlers in userspace instead of called normally. +* The long standing libgcc bug https://gcc.gnu.org/PR124050 requires a +* nop between .cfi_startproc and the actual address of the trampoline, so +* we cannot simply use SYM_FUNC_START. +* +* This wrapper also contains all the .cfi_* directives for recovering +* the content of the GPRs and the "return address" (where the rt_sigreturn +* syscall will jump to), assuming there is a struct rt_sigframe (where +* a struct sigcontext containing those information we need to recover) at +* $sp. The "DWARF for the LoongArch(TM) Architecture" manual states +* column 0 is for $zero, but it does not make too much sense to +* save/restore the hardware zero register. Repurpose this column here +* for the return address (here it's not the content of $ra we cannot use +* the default column 3). + */ +#define SYM_SIGFUNC_START (name) \ + .cfi_startproc; \ + .cfi_signal_frame; \ + .cfi_def_cfa 3, RT_SIGFRAME_SC; \ + .cfi_return_column 0; \ + .cfi_offset 0, SC_PC; \ + \ + .irp num, 1, 2, 3, 4, 5, 6, 7, 8, \ + 9, 10, 11, 12, 13, 14, 15, 16, \ + 17, 18, 19, 20, 21, 22, 23, 24, \ + 25, 26, 27, 28, 29, 30, 31; \ + .cfi_offset \num, SC_REGS + \num * SZREG; \ + .endr; \ + \ + nop; \ + SYM_START(name, SYM_L_GLOBAL, SYM_A_ALIGN) + +#define SYM_SIGFUNC_END (name) SYM_FUNC_END(name) +#endif
arch/loongarch/include/asm/sigframe.h new file +9 -0
@@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#include <asm/siginfo.h> +#include <asm/ucontext.h> + +struct rt_sigframe { +struct siginfo rs_info; +struct ucontext rs_uctx; +};
arch/loongarch/kernel/asm-offsets.c +2 -0
@@ -16,6 +16,7 @@#include <asm/ptrace.h> #include <asm/processor.h> #include <asm/ftrace.h> +#include <asm/sigframe.h> #include <vdso/datapage.h> static void __used output_ptreg_defines (void )
@@ -220,6 +221,7 @@ static void __used output_sc_defines(voiCOMMENT ("Linux sigcontext offsets." );OFFSET (SC_REGS , sigcontext, sc_regs);OFFSET (SC_PC , sigcontext, sc_pc); +OFFSET (RT_SIGFRAME_SC , rt_sigframe, rs_uctx.uc_mcontext);BLANK (); }
arch/loongarch/kernel/signal.c +1 -5
@@ -35,6 +35,7 @@#include <asm/cpu-features.h> #include <asm/fpu.h> #include <asm/lbt.h> +#include <asm/sigframe.h> #include <asm/ucontext.h> #include <asm/vdso.h>
@@ -51,11 +52,6 @@#define lock_lbt_owner () ({ preempt_disable(); pagefault_disable(); })#define unlock_lbt_owner () ({ pagefault_enable(); preempt_enable(); }) -struct rt_sigframe { -struct siginfo rs_info; -struct ucontext rs_uctx; -}; -struct _ctx_layout {struct sctx_info *addr;unsigned int size;
arch/loongarch/vdso/Makefile +2 -2
@@ -26,7 +26,7 @@ cflags-vdso := $(ccflags-vdso) \ $(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \ -std=gnu11 -fms-extensions -O2 -g -fno-strict-aliasing -fno-common -fno-builtin \ -fno-stack-protector -fno-jump-tables -DDISABLE_BRANCH_PROFILING \ - $(call cc-option, -fno-asynchronous-unwind-tables) \ + $(call cc-option, -fasynchronous-unwind-tables) \ $(call cc-option, -fno-stack-protector) aflags-vdso := $(ccflags-vdso) \ -D__ASSEMBLY__ -Wa,-gdwarf-2
@@ -41,7 +41,7 @@ endif # VDSO linker flags. ldflags-y := -Bsymbolic --no-undefined -soname=linux-vdso.so.1 \ - $(filter -E%,$(KBUILD_CFLAGS)) -shared --build-id -T + $(filter -E%,$(KBUILD_CFLAGS)) -shared --build-id --eh-frame-hdr -T # # Shared build commands.
arch/loongarch/vdso/sigreturn.S +3 -3
@@ -12,13 +12,13 @@ #include <asm/regdef.h> #include <asm/asm.h> +#include <asm/asm-offsets.h> .section .text - .cfi_sections .debug_frame -SYM_FUNC_START(__vdso_rt_sigreturn) +SYM_SIGFUNC_START(__vdso_rt_sigreturn) li.w a7, __NR_rt_sigreturn syscall 0 -SYM_FUNC_END(__vdso_rt_sigreturn) +SYM_SIGFUNC_END(__vdso_rt_sigreturn)
Greg Kroah-Hartman
maintainerPATCH 272/342 LoongArch: Workaround LS2K/LS7A GPU DMA hang bug
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Huacai Chen <[email protected]>
commit 95db0c9f526d583634cddb2e5914718570fbac87 upstream.
1. Hardware limitation: GPU, DC and VPU are typically PCI device 06.0, 06.1 and 06.2. They share some hardware resources, so when configure the PCI 06.0 device BAR1, DMA memory access cannot be performed through this BAR, otherwise it will cause hardware abnormalities.
2. In typical scenarios of reboot or S3/S4, DC access to memory through BAR is not prohibited, resulting in GPU DMA hangs.
3. Workaround method: When configuring the 06.0 device BAR1, turn off the memory access of DC, GPU and VPU (via DC's CRTC registers).
--- arch/loongarch/pci/pci.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+)
arch/loongarch/pci/pci.c +80 -0
@@ -5,9 +5,11 @@#include <linux/kernel.h> #include <linux/init.h> #include <linux/acpi.h> +#include <linux/delay.h> #include <linux/types.h> #include <linux/pci.h> #include <linux/vgaarb.h> +#include <linux/io-64-nonatomic-lo-hi.h> #include <asm/cacheflush.h> #include <asm/loongson.h>
@@ -15,6 +17,9 @@#define PCI_DEVICE_ID_LOONGSON_DC1 0x7a06#define PCI_DEVICE_ID_LOONGSON_DC2 0x7a36#define PCI_DEVICE_ID_LOONGSON_DC3 0x7a46 +#define PCI_DEVICE_ID_LOONGSON_GPU1 0x7a15 +#define PCI_DEVICE_ID_LOONGSON_GPU2 0x7a25 +#define PCI_DEVICE_ID_LOONGSON_GPU3 0x7a35int raw_pci_read (unsigned int domain,unsigned int bus,unsigned int devfn,int reg,int len,u32 *val)
@@ -99,3 +104,78 @@ static void pci_fixup_vgadev(struct pci_DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_LOONGSON ,PCI_DEVICE_ID_LOONGSON_DC1 , pci_fixup_vgadev);DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_LOONGSON ,PCI_DEVICE_ID_LOONGSON_DC2 , pci_fixup_vgadev);DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_LOONGSON ,PCI_DEVICE_ID_LOONGSON_DC3 , pci_fixup_vgadev); + +#define CRTC_NUM_MAX 2 +#define CRTC_OUTPUT_ENABLE 0x100 + +static void loongson_gpu_fixup_dma_hang (struct pci_dev *pdev,bool on) +{ +u32 i, val, count, crtc_offset, device; +void __iomem *crtc_reg, *base, *regbase; +static u32 crtc_status[CRTC_NUM_MAX ] = {0 }; + + base = pdev->bus->ops->map_bus (pdev->bus, pdev->devfn +1 ,0 ); + device =readw (base +PCI_DEVICE_ID ); + + regbase =ioremap (readq (base +PCI_BASE_ADDRESS_0 ) & ~0xffull ,SZ_64K ); +if (!regbase) { +pci_err (pdev,"Failed to ioremap()\n" ); +return ; + } + +switch (device) { +case PCI_DEVICE_ID_LOONGSON_DC2 : + crtc_reg = regbase +0x1240 ; + crtc_offset =0x10 ; +break ; +case PCI_DEVICE_ID_LOONGSON_DC3 : + crtc_reg = regbase; + crtc_offset =0x400 ; +break ; + } + +for (i =0 ; i <CRTC_NUM_MAX ; i++, crtc_reg += crtc_offset) { + val =readl (crtc_reg); + +if (!on) + crtc_status[i] = val; + +/* No need to fixup if the status is off at startup. */ +if (!(crtc_status[i] &CRTC_OUTPUT_ENABLE )) +continue ; + +if (on) + val |=CRTC_OUTPUT_ENABLE ; +else + val &= ~CRTC_OUTPUT_ENABLE ; + +mb (); +writel (val, crtc_reg); + +for (count =0 ; count <40 ; count++) { + val =readl (crtc_reg) &CRTC_OUTPUT_ENABLE ; +if ((on && val) || (!on && !val)) +break ; +udelay (1000 ); + } + +pci_info (pdev,"DMA hang fixup at reg[0x%lx]: 0x%x\n" , + (unsigned long )crtc_reg &0xffff ,readl (crtc_reg)); + } + +iounmap (regbase); +} + +static void pci_fixup_dma_hang_early (struct pci_dev *pdev) +{ +loongson_gpu_fixup_dma_hang (pdev, false); +} +DECLARE_PCI_FIXUP_EARLY (PCI_VENDOR_ID_LOONGSON ,PCI_DEVICE_ID_LOONGSON_GPU2 , pci_fixup_dma_hang_early); +DECLARE_PCI_FIXUP_EARLY (PCI_VENDOR_ID_LOONGSON ,PCI_DEVICE_ID_LOONGSON_GPU3 , pci_fixup_dma_hang_early); + +static void pci_fixup_dma_hang_final (struct pci_dev *pdev) +{ +loongson_gpu_fixup_dma_hang (pdev, true); +} +DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_LOONGSON ,PCI_DEVICE_ID_LOONGSON_GPU2 , pci_fixup_dma_hang_final); +DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_LOONGSON ,PCI_DEVICE_ID_LOONGSON_GPU3 , pci_fixup_dma_hang_final);
Greg Kroah-Hartman
maintainerPATCH 273/342 LoongArch: KVM: Make kvm_get_vcpu_by_cpuid() more robust
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Huacai Chen <[email protected]>
commit 2db06c15d8c7a0ccb6108524e16cd9163753f354 upstream.
kvm_get_vcpu_by_cpuid() takes a cpuid parameter whose type is int, so cpuid can be negative. Let kvm_get_vcpu_by_cpuid() return NULL for this case so as to make it more robust.
This fix an out-of-bounds access to kvm_arch::phyid_map::phys_map[].
--- arch/loongarch/kvm/vcpu.c | 3 +++ 1 file changed, 3 insertions(+)
arch/loongarch/kvm/vcpu.c +3 -0
@@ -562,6 +562,9 @@ struct kvm_vcpu *kvm_get_vcpu_by_cpuid(s {struct kvm_phyid_map *map; +if (cpuid <0 ) +return NULL ; +if (cpuid >=KVM_MAX_PHYID )return NULL ;
Greg Kroah-Hartman
maintainerPATCH 274/342 LoongArch: KVM: Fix base address calculation in kvm_eiointc_regs_access()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bibo Mao <[email protected]>
commit 6bcfb7f46d667b04bd1a1169ccedf5fb699c60df upstream.
In function kvm_eiointc_regs_access(), the register base address is caculated from array base address plus offset, the offset is absolute value from the base address. The data type of array base address is u64, it should be converted into the "void *" type and then plus the offset.
--- arch/loongarch/kvm/intc/eiointc.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
arch/loongarch/kvm/intc/eiointc.c +7 -7
@@ -481,34 +481,34 @@ static int kvm_eiointc_regs_access(strucswitch (addr) { case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END: offset = (addr -EIOINTC_NODETYPE_START ) /4 ; - p = s->nodetype + offset *4 ; + p = (void *)s->nodetype + offset *4 ;break ; case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END: offset = (addr -EIOINTC_IPMAP_START ) /4 ; - p = &s->ipmap + offset *4 ; + p = (void *)&s->ipmap + offset *4 ;break ; case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END: offset = (addr -EIOINTC_ENABLE_START ) /4 ; - p = s->enable + offset *4 ; + p = (void *)s->enable + offset *4 ;break ; case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END: offset = (addr -EIOINTC_BOUNCE_START ) /4 ; - p = s->bounce + offset *4 ; + p = (void *)s->bounce + offset *4 ;break ; case EIOINTC_ISR_START ... EIOINTC_ISR_END: offset = (addr -EIOINTC_ISR_START ) /4 ; - p = s->isr + offset *4 ; + p = (void *)s->isr + offset *4 ;break ; case EIOINTC_COREISR_START ... EIOINTC_COREISR_END:if (cpu >= s->num_cpu)return -EINVAL ; offset = (addr -EIOINTC_COREISR_START ) /4 ; - p = s->coreisr[cpu] + offset *4 ; + p = (void *)s->coreisr[cpu] + offset *4 ;break ; case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END: offset = (addr -EIOINTC_COREMAP_START ) /4 ; - p = s->coremap + offset *4 ; + p = (void *)s->coremap + offset *4 ;break ;default :kvm_err ("%s: unknown eiointc register, addr = %d\n" , __func__, addr);
Greg Kroah-Hartman
maintainerPATCH 275/342 LoongArch: KVM: Handle the case that EIOINTCs coremap is empty
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Huacai Chen <[email protected]>
commit b97bd69eb0f67b5f961b304d28e9ba45e202d841 upstream.
EIOINTC's coremap in eiointc_update_sw_coremap() can be empty, currently we get a cpuid with -1 in this case, but we actually need 0 because it's similar as the case that cpuid >= 4.
This fix an out-of-bounds access to kvm_arch::phyid_map::phys_map[].
--- arch/loongarch/kvm/intc/eiointc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/loongarch/kvm/intc/eiointc.c +1 -1
@@ -83,7 +83,7 @@ static inline void eiointc_update_sw_corif (!(s->status &BIT (EIOINTC_ENABLE_CPU_ENCODE ))) { cpuid =ffs (cpuid) -1 ; - cpuid = (cpuid >=4 ) ?0 : cpuid; + cpuid = ((cpuid <0 ) || (cpuid >=4 )) ?0 : cpuid; } vcpu =kvm_get_vcpu_by_cpuid (s->kvm, cpuid);
Greg Kroah-Hartman
maintainerPATCH 276/342 drm/amd/pm: Return -EOPNOTSUPP for unsupported OD_MCLK on smu_v13_0_6
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Asad Kamal <[email protected]>
commit 2f0e491faee43181b6a86e90f34016b256042fe1 upstream.
When SET_UCLK_MAX capability is absent, return -EOPNOTSUPP from smu_v13_0_6_emit_clk_levels() for OD_MCLK instead of 0. This makes unsupported OD_MCLK reporting consistent with other clock types and allows callers to skip the entry cleanly.
--- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +1 -1
@@ -1520,7 +1520,7 @@ static int smu_v13_0_6_print_clk_levels(case SMU_OD_MCLK :if (!smu_v13_0_6_cap_supported (smu,SMU_CAP (SET_UCLK_MAX ))) -return 0 ; +return -EOPNOTSUPP ; size +=sysfs_emit_at (buf, size,"%s:\n" ,"OD_MCLK" ); size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMhz\n",
Greg Kroah-Hartman
maintainerPATCH 277/342 mm/memory: fix PMD/PUD checks in follow_pfnmap_start()
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Hildenbrand (Arm) <[email protected]>
commit ffef67b93aa352b34e6aeba3d52c19a63885409a upstream.
follow_pfnmap_start() suffers from two problems:
(1) We are not re-fetching the pmd/pud after taking the PTL
Therefore, we are not properly stabilizing what the lock actually protects. If there is concurrent zapping, we would indicate to the caller that we found an entry, however, that entry might already have been invalidated, or contain a different PFN after taking the lock.
Properly use pmdp_get() / pudp_get() after taking the lock.
(2) pmd_leaf() / pud_leaf() are not well defined on non-present entries
pmd_leaf()/pud_leaf() could wrongly trigger on non-present entries.
There is no real guarantee that pmd_leaf()/pud_leaf() returns something reasonable on non-present entries. Most architectures indeed either perform a present check or make it work by smart use of flags.
However, for example loongarch checks the _PAGE_HUGE flag in pmd_leaf(), and always sets the _PAGE_HUGE flag in __swp_entry_to_pmd(). Whereby pmd_trans_huge() explicitly checks pmd_present(), pmd_leaf() does not do that.
Let's check pmd_present()/pud_present() before assuming "the is a present PMD leaf" when spotting pmd_leaf()/pud_leaf(), like other page table handling code that traverses user page tables does.
Given that non-present PMD entries are likely rare in VM_IO|VM_PFNMAP, (1) is likely more relevant than (2). It is questionable how often (1) would actually trigger, but let's CC stable to be sure.
This was found by code inspection.
--- mm/memory.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-)
mm/memory.c +15 -3
@@ -6775,11 +6775,16 @@ retry: pudp =pud_offset (p4dp, address); pud =pudp_get (pudp); -if (pud_none (pud)) +if (!pud_present (pud)) goto out;if (pud_leaf (pud)) { lock =pud_lock (mm, pudp); -if (!unlikely (pud_leaf (pud))) { + pud =pudp_get (pudp); + +if (unlikely (!pud_present (pud))) { +spin_unlock (lock); + goto out; + }else if (unlikely (!pud_leaf (pud))) {spin_unlock (lock); goto retry; }
@@ -6791,9 +6796,16 @@ retry: pmdp =pmd_offset (pudp, address); pmd =pmdp_get_lockless (pmdp); +if (!pmd_present (pmd)) + goto out;if (pmd_leaf (pmd)) { lock =pmd_lock (mm, pmdp); -if (!unlikely (pmd_leaf (pmd))) { + pmd =pmdp_get (pmdp); + +if (unlikely (!pmd_present (pmd))) { +spin_unlock (lock); + goto out; + }else if (unlikely (!pmd_leaf (pmd))) {spin_unlock (lock); goto retry; }
Greg Kroah-Hartman
maintainerPATCH 278/342 mm/mseal: update VMA end correctly on merge
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Stoakes (Oracle) <[email protected]>
commit 2697dd8ae721db4f6a53d4f4cbd438212a80f8dc upstream.
Previously we stored the end of the current VMA in curr_end, and then upon iterating to the next VMA updated curr_start to curr_end to advance to the next VMA.
However, this doesn't take into account the fact that a VMA might be updated due to a merge by vma_modify_flags(), which can result in curr_end being stale and thus, upon setting curr_start to curr_end, ending up with an incorrect curr_start on the next iteration.
Resolve the issue by setting curr_end to vma->vm_end unconditionally to ensure this value remains updated should this occur.
While we're here, eliminate this entire class of bug by simply setting const curr_[start/end] to be clamped to the input range and VMAs, which also happens to simplify the logic.
--- mm/mseal.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
mm/mseal.c +1 -2
@@ -56,7 +56,6 @@ static int mseal_apply(struct mm_struct unsigned long start, unsigned long end) {struct vm_area_struct *vma, *prev; -unsigned long curr_start = start;VMA_ITERATOR (vmi, mm, start);/* We know there are no gaps so this will be non-NULL. */
@@ -66,6 +65,7 @@ static int mseal_apply(struct mm_struct prev = vma;for_each_vma_range (vmi, vma, end) { +const unsigned long curr_start =MAX (vma->vm_start, start);const unsigned long curr_end =MIN (vma->vm_end, end);if (!(vma->vm_flags &VM_SEALED )) {
@@ -79,7 +79,6 @@ static int mseal_apply(struct mm_struct } prev = vma; - curr_start = curr_end; }return 0 ;
Greg Kroah-Hartman
maintainerPATCH 279/342 mm/damon/sysfs: fix param_ctx leak on damon_sysfs_new_test_ctx() failure
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Josh Law <[email protected]>
commit 7fe000eb32904758a85e62f6ea9483f89d5dabfc upstream.
Patch series "mm/damon/sysfs: fix memory leak and NULL dereference issues", v4.
DAMON_SYSFS can leak memory under allocation failure, and do NULL pointer dereference when a privileged user make wrong sequences of control. Fix those.
This patch (of 3):
When damon_sysfs_new_test_ctx() fails in damon_sysfs_commit_input(), param_ctx is leaked because the early return skips the cleanup at the out label. Destroy param_ctx before returning.
--- mm/damon/sysfs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
mm/damon/sysfs.c +3 -1
@@ -1526,8 +1526,10 @@ static int damon_sysfs_commit_input(voidif (IS_ERR (param_ctx))return PTR_ERR (param_ctx); test_ctx =damon_sysfs_new_test_ctx (kdamond->damon_ctx); -if (!test_ctx) +if (!test_ctx) { +damon_destroy_ctx (param_ctx);return -ENOMEM ; + } err =damon_commit_ctx (test_ctx, param_ctx);if (err) goto out;
Greg Kroah-Hartman
maintainerPATCH 280/342 mm/damon/sysfs: check contexts->nr before accessing contexts_arr[0]
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Josh Law <[email protected]>
commit 1bfe9fb5ed2667fb075682408b776b5273162615 upstream.
Multiple sysfs command paths dereference contexts_arr[0] without first verifying that kdamond->contexts->nr == 1. A user can set nr_contexts to 0 via sysfs while DAMON is running, causing NULL pointer dereferences.
In more detail, the issue can be triggered by privileged users like below.
First, start DAMON and make contexts directory empty (kdamond->contexts->nr == 0).
# damo start
# cd /sys/kernel/mm/damon/admin/kdamonds/0
# echo 0 > contexts/nr_contextsThen, each of below commands will cause the NULL pointer dereference.
# echo update_schemes_stats > state
# echo update_schemes_tried_regions > state
# echo update_schemes_tried_bytes > state
# echo update_schemes_effective_quotas > state
# echo update_tuned_intervals > stateGuard all commands (except OFF) at the entry point of damon_sysfs_handle_cmd().
--- mm/damon/sysfs.c | 3 +++ 1 file changed, 3 insertions(+)
mm/damon/sysfs.c +3 -0
@@ -1752,6 +1752,9 @@ static int damon_sysfs_update_schemes_trstatic int damon_sysfs_handle_cmd (enum damon_sysfs_cmd cmd,struct damon_sysfs_kdamond *kdamond) { +if (cmd !=DAMON_SYSFS_CMD_OFF && kdamond->contexts->nr !=1 ) +return -EINVAL ; +switch (cmd) {case DAMON_SYSFS_CMD_ON :return damon_sysfs_turn_damon_on (kdamond);
Greg Kroah-Hartman
maintainerPATCH 281/342 mm/damon/sysfs: check contexts->nr in repeat_call_fn
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Josh Law <[email protected]>
commit 6557004a8b59c7701e695f02be03c7e20ed1cc15 upstream.
damon_sysfs_repeat_call_fn() calls damon_sysfs_upd_tuned_intervals(), damon_sysfs_upd_schemes_stats(), and damon_sysfs_upd_schemes_effective_quotas() without checking contexts->nr. If nr_contexts is set to 0 via sysfs while DAMON is running, these functions dereference contexts_arr[0] and cause a NULL pointer dereference. Add the missing check.
For example, the issue can be reproduced using DAMON sysfs interface and DAMON user-space tool (damo) [1] like below.
$ sudo damo start --refresh_interval 1s
$ echo 0 | sudo tee \
/sys/kernel/mm/damon/admin/kdamonds/0/contexts/nr_contexts--- mm/damon/sysfs.c | 3 +++ 1 file changed, 3 insertions(+)
mm/damon/sysfs.c +3 -0
@@ -1622,9 +1622,12 @@ static int damon_sysfs_repeat_call_fn(voif (!mutex_trylock (&damon_sysfs_lock))return 0 ; +if (sysfs_kdamond->contexts->nr !=1 ) + goto out;damon_sysfs_upd_tuned_intervals (sysfs_kdamond);damon_sysfs_upd_schemes_stats (sysfs_kdamond);damon_sysfs_upd_schemes_effective_quotas (sysfs_kdamond); +out:mutex_unlock (&damon_sysfs_lock);return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 282/342 mm/pagewalk: fix race between concurrent split and refault
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Max Boone <[email protected]>
commit 3b89863c3fa482912911cd65a12a3aeef662c250 upstream.
The splitting of a PUD entry in walk_pud_range() can race with a concurrent thread refaulting the PUD leaf entry causing it to try walking a PMD range that has disappeared.
An example and reproduction of this is to try reading numa_maps of a process while VFIO-PCI is setting up DMA (specifically the vfio_pin_pages_remote call) on a large BAR for that process.
This will trigger a kernel BUG:
vfio-pci 0000:03:00.0: enabling device (0000 -> 0002)
BUG: unable to handle page fault for address: ffffa23980000000 PGD 0 P4D 0 Oops: Oops: 0000 [#1] SMP NOPTI ... RIP: 0010:walk_pgd_range+0x3b5/0x7a0 Code: 8d 43 ff 48 89 44 24 28 4d 89 ce 4d 8d a7 00 00 20 00 48 8b 4c 24 28 49 81 e4 00 00 e0 ff 49 8d 44 24 ff 48 39 c8 4c 0f 43 e3 <49> f7 06 9f ff ff ff 75 3b 48 8b 44 24 20 48 8b 40 28 48 85 c0 74 RSP: 0018:ffffac23e1ecf808 EFLAGS: 00010287 RAX: 00007f44c01fffff RBX: 00007f4500000000 RCX: 00007f44ffffffff RDX: 0000000000000000 RSI: 000ffffffffff000 RDI: ffffffff93378fe0 RBP: ffffac23e1ecf918 R08: 0000000000000004 R09: ffffa23980000000 R10: 0000000000000020 R11: 0000000000000004 R12: 00007f44c0200000 R13: 00007f44c0000000 R14: ffffa23980000000 R15: 00007f44c0000000 FS: 00007fe884739580(0000) GS:ffff9b7d7a9c0000(0000)
knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: ffffa23980000000 CR3: 000000c0650e2005 CR4: 0000000000770ef0
PKRU: 55555554
Call Trace: <TASK> __walk_page_range+0x195/0x1b0 walk_page_vma+0x62/0xc0 show_numa_map+0x12b/0x3b0 seq_read_iter+0x297/0x440 seq_read+0x11d/0x140 vfs_read+0xc2/0x340 ksys_read+0x5f/0xe0 do_syscall_64+0x68/0x130 ? get_page_from_freelist+0x5c2/0x17e0 ? mas_store_prealloc+0x17e/0x360 ? vma_set_page_prot+0x4c/0xa0 ? __alloc_pages_noprof+0x14e/0x2d0 ? __mod_memcg_lruvec_state+0x8d/0x140 ? __lruvec_stat_mod_folio+0x76/0xb0 ? __folio_mod_stat+0x26/0x80 ? do_anonymous_page+0x705/0x900 ? __handle_mm_fault+0xa8d/0x1000 ? __count_memcg_events+0x53/0xf0 ? handle_mm_fault+0xa5/0x360 ? do_user_addr_fault+0x342/0x640 ? arch_exit_to_user_mode_prepare.constprop.0+0x16/0xa0 ? irqentry_exit_to_user_mode+0x24/0x100 entry_SYSCALL_64_after_hwframe+0x76/0x7e RIP: 0033:0x7fe88464f47e Code: c0 e9 b6 fe ff ff 50 48 8d 3d be 07 0b 00 e8 69 01 02 00 66 0f 1f
84 00 00 00 00 00 64 8b 04 25 18 00 00 00 85 c0 75 14 0f 05 <48> 3d 00
f0 ff ff 77 5a c3 66 0f 1f 84 00 00 00 00 00 48 83 ec 28
RSP: 002b:00007ffe6cd9a9b8 EFLAGS: 00000246 ORIG_RAX: 0000000000000000
RAX: ffffffffffffffda RBX: 0000000000020000 RCX: 00007fe88464f47e
RDX: 0000000000020000 RSI: 00007fe884543000 RDI: 0000000000000003
RBP: 00007fe884543000 R08: 00007fe884542010 R09: 0000000000000000
R10: fffffffffffffbc5 R11: 0000000000000246 R12: 0000000000000000
R13: 0000000000000003 R14: 0000000000020000 R15: 0000000000020000
</TASK>
Fix this by validating the PUD entry in walk_pmd_range() using a stable snapshot (pudp_get()). If the PUD is not present or is a leaf, retry the walk via ACTION_AGAIN instead of descending further. This mirrors the retry logic in walk_pte_range(), which lets walk_pmd_range() retry if the PTE is not being got by pte_offset_map_lock().
--- mm/pagewalk.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-)
mm/pagewalk.c +22 -3
@@ -97,6 +97,7 @@ static int walk_pte_range(pmd_t *pmd, unstatic int walk_pmd_range (pud_t *pud,unsigned long addr,unsigned long end,struct mm_walk *walk) { +pud_t pudval =pudp_get (pud);pmd_t *pmd;unsigned long next;const struct mm_walk_ops *ops = walk->ops;
@@ -105,6 +106,24 @@ static int walk_pmd_range(pud_t *pud, unint err =0 ;int depth =real_depth (3 ); +/* +* For PTE handling, pte_offset_map_lock() takes care of checking +* whether there actually is a page table. But it also has to be +* very careful about concurrent page table reclaim. +* +* Similarly, we have to be careful here - a PUD entry that points +* to a PMD table cannot go away, so we can just walk it. But if +* it's something else, we need to ensure we didn't race something, +* so need to retry. +* +* A pertinent example of this is a PUD refault after PUD split - +* we will need to split again or risk accessing invalid memory. +*/ +if (!pud_present (pudval) ||pud_leaf (pudval)) { + walk->action =ACTION_AGAIN ; +return 0 ; + } + pmd =pmd_offset (pud, addr); do { again:
@@ -218,12 +237,12 @@ static int walk_pud_range(p4d_t *p4d, unelse if (pud_leaf (*pud) || !pud_present (*pud))continue ;/* Nothing to do. */ -if (pud_none (*pud)) - goto again; - err =walk_pmd_range (pud, addr, next, walk);if (err)break ; + +if (walk->action ==ACTION_AGAIN ) + goto again; }while (pud++, addr = next, addr != end);return err;
Greg Kroah-Hartman
maintainerPATCH 283/342 xfs: stop reclaim before pushing AIL during unmount
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuto Ohnuki <[email protected]>
commit 4f24a767e3d64a5f58c595b5c29b6063a201f1e3 upstream.
The unmount sequence in xfs_unmount_flush_inodes() pushed the AIL while background reclaim and inodegc are still running. This is broken independently of any use-after-free issues - background reclaim and inodegc should not be running while the AIL is being pushed during unmount, as inodegc can dirty and insert inodes into the AIL during the flush, and background reclaim can race to abort and free dirty inodes.
Reorder xfs_unmount_flush_inodes() to stop inodegc and cancel background reclaim before pushing the AIL. Stop inodegc before cancelling m_reclaim_work because the inodegc worker can re-queue m_reclaim_work via xfs_inodegc_set_reclaimable.
--- fs/xfs/xfs_mount.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
fs/xfs/xfs_mount.c +4 -3
@@ -607,8 +607,9 @@ xfs_unmount_check(* have been retrying in the background. This will prevent never-ending * retries in AIL pushing from hanging the unmount. * -* Finally, we can push the AIL to clean all the remaining dirty objects, then -* reclaim the remaining inodes that are still in memory at this point in time. +* Stop inodegc and background reclaim before pushing the AIL so that they +* are not running while the AIL is being flushed. Then push the AIL to +* clean all the remaining dirty objects and reclaim the remaining inodes. */ static void xfs_unmount_flush_inodes(
@@ -620,9 +621,9 @@ xfs_unmount_flush_inodes(xfs_set_unmounting (mp); -xfs_ail_push_all_sync (mp->m_ail);xfs_inodegc_stop (mp);cancel_delayed_work_sync (&mp->m_reclaim_work); +xfs_ail_push_all_sync (mp->m_ail);xfs_reclaim_inodes (mp);xfs_health_unmount (mp); }
Greg Kroah-Hartman
maintainerPATCH 284/342 xfs: save ailp before dropping the AIL lock in push callbacks
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuto Ohnuki <[email protected]>
commit 394d70b86fae9fe865e7e6d9540b7696f73aa9b6 upstream.
In xfs_inode_item_push() and xfs_qm_dquot_logitem_push(), the AIL lock is dropped to perform buffer IO. Once the cluster buffer no longer protects the log item from reclaim, the log item may be freed by background reclaim or the dquot shrinker. The subsequent spin_lock() call dereferences lip->li_ailp, which is a use-after-free.
Fix this by saving the ailp pointer in a local variable while the AIL lock is held and the log item is guaranteed to be valid.
--- fs/xfs/xfs_dquot_item.c | 9 +++++++-- fs/xfs/xfs_inode_item.c | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-)
fs/xfs/xfs_dquot_item.c +7 -2
@@ -126,6 +126,7 @@ xfs_qm_dquot_logitem_push(struct xfs_dq_logitem *qlip =DQUOT_ITEM (lip);struct xfs_dquot *dqp = qlip->qli_dquot;struct xfs_buf *bp; +struct xfs_ail *ailp = lip->li_ailp;uint rval =XFS_ITEM_SUCCESS ;int error;
@@ -154,7 +155,7 @@ xfs_qm_dquot_logitem_push( goto out_unlock; } -spin_unlock (&lip->li_ailp->ail_lock); +spin_unlock (&ailp->ail_lock); error =xfs_dquot_use_attached_buf (dqp, &bp);if (error == -EAGAIN ) {
@@ -173,9 +174,13 @@ xfs_qm_dquot_logitem_push( rval =XFS_ITEM_FLUSHING ; }xfs_buf_relse (bp); +/* +* The buffer no longer protects the log item from reclaim, so +* do not reference lip after this point. +*/ out_relock_ail: -spin_lock (&lip->li_ailp->ail_lock); +spin_lock (&ailp->ail_lock); out_unlock:mutex_unlock (&dqp->q_qlock);return rval;
fs/xfs/xfs_inode_item.c +7 -2
@@ -749,6 +749,7 @@ xfs_inode_item_push(struct xfs_inode_log_item *iip =INODE_ITEM (lip);struct xfs_inode *ip = iip->ili_inode;struct xfs_buf *bp = lip->li_buf; +struct xfs_ail *ailp = lip->li_ailp;uint rval =XFS_ITEM_SUCCESS ;int error;
@@ -774,7 +775,7 @@ xfs_inode_item_push(if (!xfs_buf_trylock (bp))return XFS_ITEM_LOCKED ; -spin_unlock (&lip->li_ailp->ail_lock); +spin_unlock (&ailp->ail_lock);/* * We need to hold a reference for flushing the cluster buffer as it may
@@ -798,7 +799,11 @@ xfs_inode_item_push( rval =XFS_ITEM_LOCKED ; } -spin_lock (&lip->li_ailp->ail_lock); +/* +* The buffer no longer protects the log item from reclaim, so +* do not reference lip after this point. +*/ +spin_lock (&ailp->ail_lock);return rval; }
Greg Kroah-Hartman
maintainerPATCH 285/342 xfs: avoid dereferencing log items after push callbacks
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuto Ohnuki <[email protected]>
commit 79ef34ec0554ec04bdbafafbc9836423734e1bd6 upstream.
After xfsaild_push_item() calls iop_push(), the log item may have been freed if the AIL lock was dropped during the push. Background inode reclaim or the dquot shrinker can free the log item while the AIL lock is not held, and the tracepoints in the switch statement dereference the log item after iop_push() returns.
Fix this by capturing the log item type, flags, and LSN before calling xfsaild_push_item(), and introducing a new xfs_ail_push_class trace event class that takes these pre-captured values and the ailp pointer instead of the log item pointer.
--- fs/xfs/xfs_trace.h | 36 ++++++++++++++++++++++++++++++++---- fs/xfs/xfs_trans_ail.c | 26 +++++++++++++++++++------- 2 files changed, 51 insertions(+), 11 deletions(-)
fs/xfs/xfs_trace.h +32 -4
@@ -56,6 +56,7 @@#include <linux/tracepoint.h> struct xfs_agf ; +struct xfs_ail ;struct xfs_alloc_arg ;struct xfs_attr_list_context ;struct xfs_buf_log_item ;
@@ -1647,16 +1648,43 @@ TRACE_EVENT(xfs_log_force,DEFINE_EVENT (xfs_log_item_class, name, \ TP_PROTO(struct xfs_log_item *lip), \ TP_ARGS(lip)) -DEFINE_LOG_ITEM_EVENT (xfs_ail_push); -DEFINE_LOG_ITEM_EVENT (xfs_ail_pinned); -DEFINE_LOG_ITEM_EVENT (xfs_ail_locked); -DEFINE_LOG_ITEM_EVENT (xfs_ail_flushing);DEFINE_LOG_ITEM_EVENT (xfs_cil_whiteout_mark);DEFINE_LOG_ITEM_EVENT (xfs_cil_whiteout_skip);DEFINE_LOG_ITEM_EVENT (xfs_cil_whiteout_unpin);DEFINE_LOG_ITEM_EVENT (xlog_ail_insert_abort);DEFINE_LOG_ITEM_EVENT (xfs_trans_free_abort); +DECLARE_EVENT_CLASS (xfs_ail_push_class, + TP_PROTO(struct xfs_ail *ailp, uint type, unsigned long flags, xfs_lsn_t lsn), +TP_ARGS (ailp, type, flags, lsn), +TP_STRUCT__entry ( + __field(dev_t, dev) + __field(uint, type) + __field(unsigned long, flags) +__field (xfs_lsn_t, lsn) + ), +TP_fast_assign ( + __entry->dev = ailp->ail_log->l_mp->m_super->s_dev; + __entry->type = type; + __entry->flags = flags; + __entry->lsn = lsn; + ), +TP_printk ("dev %d:%d lsn %d/%d type %s flags %s" , +MAJOR (__entry->dev),MINOR (__entry->dev), +CYCLE_LSN (__entry->lsn),BLOCK_LSN (__entry->lsn), +__print_symbolic (__entry->type,XFS_LI_TYPE_DESC ), +__print_flags (__entry->flags,"|" ,XFS_LI_FLAGS )) +) + +#define DEFINE_AIL_PUSH_EVENT (name) \ +DEFINE_EVENT(xfs_ail_push_class, name, \ + TP_PROTO(struct xfs_ail *ailp, uint type, unsigned long flags, xfs_lsn_t lsn), \ + TP_ARGS(ailp, type, flags, lsn)) +DEFINE_AIL_PUSH_EVENT (xfs_ail_push); +DEFINE_AIL_PUSH_EVENT (xfs_ail_pinned); +DEFINE_AIL_PUSH_EVENT (xfs_ail_locked); +DEFINE_AIL_PUSH_EVENT (xfs_ail_flushing); + DECLARE_EVENT_CLASS(xfs_ail_class, TP_PROTO(struct xfs_log_item *lip, xfs_lsn_t old_lsn, xfs_lsn_t new_lsn), TP_ARGS(lip, old_lsn, new_lsn),
fs/xfs/xfs_trans_ail.c +19 -7
@@ -365,6 +365,12 @@ xfsaild_resubmit_item(return XFS_ITEM_SUCCESS ; } +/* +* Push a single log item from the AIL. +* +* @lip may have been released and freed by the time this function returns, +* so callers must not dereference the log item afterwards. +*/ static inline uint xfsaild_push_item( struct xfs_ail *ailp,
@@ -505,7 +511,10 @@ xfsaild_push( lsn = lip->li_lsn;while ((XFS_LSN_CMP (lip->li_lsn, ailp->ail_target) <=0 )) { -int lock_result; +int lock_result; +uint type = lip->li_type; +unsigned long flags = lip->li_flags; +xfs_lsn_t item_lsn = lip->li_lsn;if (test_bit (XFS_LI_FLUSHING , &lip->li_flags)) goto next_item;
@@ -514,14 +523,17 @@ xfsaild_push(* Note that iop_push may unlock and reacquire the AIL lock. We * rely on the AIL cursor implementation to be able to deal with * the dropped lock. +* +* The log item may have been freed by the push, so it must not +* be accessed or dereferenced below this line. */ lock_result =xfsaild_push_item (ailp, lip);switch (lock_result) {case XFS_ITEM_SUCCESS :XFS_STATS_INC (mp, xs_push_ail_success); -trace_xfs_ail_push (lip); +trace_xfs_ail_push (ailp, type, flags, item_lsn); - ailp->ail_last_pushed_lsn = lsn; + ailp->ail_last_pushed_lsn = item_lsn;break ;case XFS_ITEM_FLUSHING :
@@ -537,22 +549,22 @@ xfsaild_push(* AIL is being flushed. */ XFS_STATS_INC (mp, xs_push_ail_flushing); -trace_xfs_ail_flushing (lip); +trace_xfs_ail_flushing (ailp, type, flags, item_lsn); flushing++; - ailp->ail_last_pushed_lsn = lsn; + ailp->ail_last_pushed_lsn = item_lsn;break ;case XFS_ITEM_PINNED :XFS_STATS_INC (mp, xs_push_ail_pinned); -trace_xfs_ail_pinned (lip); +trace_xfs_ail_pinned (ailp, type, flags, item_lsn); stuck++; ailp->ail_log_flush++;break ;case XFS_ITEM_LOCKED :XFS_STATS_INC (mp, xs_push_ail_locked); -trace_xfs_ail_locked (lip); +trace_xfs_ail_locked (ailp, type, flags, item_lsn); stuck++;break ;
Greg Kroah-Hartman
maintainerPATCH 286/342 xfs: scrub: unlock dquot before early return in quota scrub
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: hongao <[email protected]>
commit 268378b6ad20569af0d1957992de1c8b16c6e900 upstream.
xchk_quota_item can return early after calling xchk_fblock_process_error. When that helper returns false, the function returned immediately without dropping dq->q_qlock, which can leave the dquot lock held and risk lock leaks or deadlocks in later quota operations.
Fix this by unlocking dq->q_qlock before the early return.
--- fs/xfs/scrub/quota.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/xfs/scrub/quota.c +3 -1
@@ -171,8 +171,10 @@ xchk_quota_item( error =xchk_quota_item_bmap (sc, dq, offset);xchk_iunlock (sc,XFS_ILOCK_SHARED ); -if (!xchk_fblock_process_error (sc,XFS_DATA_FORK , offset, &error)) +if (!xchk_fblock_process_error (sc,XFS_DATA_FORK , offset, &error)) { +mutex_unlock (&dq->q_qlock);return error; + }/* * Warn if the hard limits are larger than the fs.
Greg Kroah-Hartman
maintainerPATCH 287/342 xfs: fix ri_total validation in xlog_recover_attri_commit_pass2
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Long Li <[email protected]>
commit d72f2084e30966097c8eae762e31986a33c3c0ae upstream.
The ri_total checks for SET/REPLACE operations are hardcoded to 3, but xfs_attri_item_size() only emits a value iovec when value_len > 0, so ri_total is 2 when value_len == 0.
For PPTR_SET/PPTR_REMOVE/PPTR_REPLACE, value_len is validated by xfs_attri_validate() to be exactly sizeof(struct xfs_parent_rec) and is never zero, so their hardcoded checks remain correct.
This problem may cause log recovery failures. The following script can be used to reproduce the problem:
#!/bin/bash
mkfs.xfs -f /dev/sda
mount /dev/sda /mnt/test/
touch /mnt/test/file
for i in {1..200}; do
attr -s "user.attr_$i" -V "value_$i" /mnt/test/file > /dev/null
done
echo 1 > /sys/fs/xfs/debug/larp
echo 1 > /sys/fs/xfs/sda/errortag/larp
attr -s "user.zero" -V "" /mnt/test/file
echo 0 > /sys/fs/xfs/sda/errortag/larp
umount /mnt/test
mount /dev/sda /mnt/test/ # mount failed
Fix this by deriving the expected count dynamically as "2 + !!value_len" for SET/REPLACE operations.
--- fs/xfs/xfs_attr_item.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/xfs/xfs_attr_item.c +2 -2
@@ -1050,8 +1050,8 @@ xlog_recover_attri_commit_pass2(break ;case XFS_ATTRI_OP_FLAGS_SET :case XFS_ATTRI_OP_FLAGS_REPLACE : -/* Log item, attr name, attr value */ -if (item->ri_total !=3 ) { +/* Log item, attr name, optional attr value */ +if (item->ri_total !=2 + !!attri_formatp->alfi_value_len) {XFS_CORRUPTION_ERROR (__func__,XFS_ERRLEVEL_LOW , mp, attri_formatp, len);return -EFSCORRUPTED ;
Greg Kroah-Hartman
maintainerPATCH 288/342 xfs: dont irele after failing to iget in xfs_attri_recover_work
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <[email protected]>
commit 70685c291ef82269180758130394ecdc4496b52c upstream.
xlog_recovery_iget* never set @ip to a valid pointer if they return an error, so this irele will walk off a dangling pointer. Fix that.
--- fs/xfs/xfs_attr_item.c | 1 - 1 file changed, 1 deletion(-)
fs/xfs/xfs_attr_item.c +0 -1
@@ -656,7 +656,6 @@ xfs_attri_recover_work(break ; }if (error) { -xfs_irele (ip);XFS_CORRUPTION_ERROR (__func__,XFS_ERRLEVEL_LOW , mp, attrp,sizeof (*attrp));return ERR_PTR (-EFSCORRUPTED );
Greg Kroah-Hartman
maintainerPATCH 289/342 xfs: remove file_path tracepoint data
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <[email protected]>
commit e31c53a8060e134111ed095783fee0aa0c43b080 upstream.
The xfile/xmbuf shmem file descriptions are no longer as detailed as they were when online fsck was first merged, because moving to static strings in commit 60382993a2e180 ("xfs: get rid of the xchk_xfile_*_descr calls") removed a memory allocation and hence a source of failure.
However this makes encoding the description in the tracepoints sort of a waste of memory. David Laight also points out that file_path doesn't zero the whole buffer which causes exposure of stale trace bytes, and Steven Rostedt wonders why we're not using a dynamic array for the file path.
I don't think this is worth fixing, so let's just rip it out.
--- fs/xfs/scrub/trace.h | 12 ++---------- fs/xfs/xfs_trace.h | 11 ++--------- 2 files changed, 4 insertions(+), 19 deletions(-)
fs/xfs/scrub/trace.h +2 -10
@@ -972,20 +972,12 @@ TRACE_EVENT(xfile_create,TP_STRUCT__entry (__field (dev_t ,dev ) __field(unsigned long, ino) -__array (char, pathname,MAXNAMELEN ) ),TP_fast_assign ( - char *path; - __entry->ino = file_inode(xf->file)->i_ino; - path =file_path (xf->file, __entry->pathname,MAXNAMELEN ); -if (IS_ERR (path)) -strncpy (__entry->pathname,"(unknown)" , -sizeof (__entry->pathname)); ), -TP_printk ("xfino 0x%lx path '%s'" , - __entry->ino, - __entry->pathname) +TP_printk ("xfino 0x%lx" , + __entry->ino) ); TRACE_EVENT(xfile_destroy,
fs/xfs/xfs_trace.h +2 -9
@@ -5115,23 +5115,16 @@ TRACE_EVENT(xmbuf_create,TP_STRUCT__entry (__field (dev_t ,dev ) __field(unsigned long, ino) -__array (char, pathname,MAXNAMELEN ) ),TP_fast_assign ( - char *path; struct file *file = btp->bt_file; __entry->dev = btp->bt_mount->m_super->s_dev; __entry->ino =file_inode (file)->i_ino; - path =file_path (file, __entry->pathname,MAXNAMELEN ); -if (IS_ERR (path)) -strncpy (__entry->pathname,"(unknown)" , -sizeof (__entry->pathname)); ), -TP_printk ("dev %d:%d xmino 0x%lx path '%s'" , +TP_printk ("dev %d:%d xmino 0x%lx" ,MAJOR (__entry->dev),MINOR (__entry->dev), - __entry->ino, - __entry->pathname) + __entry->ino) ); TRACE_EVENT(xmbuf_free,
Greg Kroah-Hartman
maintainerPATCH 290/342 ext4: fix journal credit check when setting fscrypt context
In reply to Greg Kroah-Hartman6.19-stable review patch. If anyone has any objections, please let me know.
------------------
From: Simon Weber <[email protected]>
commit b1d682f1990c19fb1d5b97d13266210457092bcd upstream.
Fix an issue arising when ext4 features has_journal, ea_inode, and encrypt are activated simultaneously, leading to ENOSPC when creating an encrypted file.
Fix by passing XATTR_CREATE flag to xattr_set_handle function if a handle is specified, i.e., when the function is called in the control flow of creating a new inode. This aligns the number of jbd2 credits set_handle checks for with the number allocated for creating a new inode.
ext4_set_context must not be called with a non-null handle (fs_data) if fscrypt context xattr is not guaranteed to not exist yet. The only other usage of this function currently is when handling the ioctl FS_IOC_SET_ENCRYPTION_POLICY, which calls it with fs_data=NULL.
--- fs/ext4/crypto.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
fs/ext4/crypto.c +8 -1
@@ -163,10 +163,17 @@ static int ext4_set_context(struct inode*/ if (handle) { +/* +* Since the inode is new it is ok to pass the +* XATTR_CREATE flag. This is necessary to match the +* remaining journal credits check in the set_handle +* function with the credits allocated for the new +* inode. +*/ res =ext4_xattr_set_handle (handle, inode,EXT4_XATTR_INDEX_ENCRYPTION ,EXT4_XATTR_NAME_ENCRYPTION_CONTEXT , - ctx, len,0 ); + ctx, len,XATTR_CREATE );if (!res) {ext4_set_inode_flag (inode,EXT4_INODE_ENCRYPT ); ext4_clear_inode_state(inode,