6.18.21-rc1 review
Subsystems (4)
Greg Kroah-Hartman
maintainerPATCH 149/309 ASoC: fsl: imx-card: initialize playback_only and capture_only
In reply to Greg Kroah-Hartman6.18-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 150/309 scsi: scsi_transport_sas: Fix the maximum channel scanning issue
In reply to Greg Kroah-Hartman6.18-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 151/309 x86/efi: efi_unmap_boot_services: fix calculation of ranges_to_free size
In reply to Greg Kroah-Hartman6.18-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 152/309 drm/mediatek: dsi: Store driver data before invoking mipi_dsi_host_register
In reply to Greg Kroah-Hartman6.18-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 153/309 drm/i915/gmbus: fix spurious timeout on 512-byte burst reads
In reply to Greg Kroah-Hartman6.18-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
@@ -497,8 +497,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 154/309 PM: hibernate: Drain trailing zero pages on userspace restore
In reply to Greg Kroah-Hartman6.18-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
@@ -2856,6 +2856,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 155/309 PM: sleep: Drop spurious WARN_ON() from pm_restore_gfp_mask()
In reply to Greg Kroah-Hartman6.18-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
@@ -38,7 +38,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 156/309 spi: sn-f-ospi: Fix resource leak in f_ospi_probe()
In reply to Greg Kroah-Hartman6.18-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 157/309 ASoC: Intel: catpt: Fix the device initialization
In reply to Greg Kroah-Hartman6.18-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
@@ -271,7 +271,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 158/309 spi: meson-spicc: Fix double-put in remove path
In reply to Greg Kroah-Hartman6.18-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 159/309 drm/amd/display: Do not skip unrelated mode changes in DSC validation
In reply to Greg Kroah-Hartman6.18-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
@@ -12268,6 +12268,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 160/309 ASoC: dt-bindings: stm32: Fix incorrect compatible string in stm32h7-sai match
In reply to Greg Kroah-Hartman6.18-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 161/309 rust: regulator: do not assume that regulator_get() returns non-null
In reply to Greg Kroah-Hartman6.18-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 {}
@@ -230,15 +233,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 >, }
@@ -250,7 +255,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 (), )
@@ -260,7 +265,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)) }
@@ -270,10 +275,8 @@ impl<T: RegulatorState> Regulator<T> {// received from the C code. let inner =from_err_ptr (unsafe { bindings::regulator_get (dev.as_raw (), name.as_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 ,
@@ -282,12 +285,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) }) } }
@@ -349,7 +352,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 } } }
@@ -359,11 +362,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 162/309 drm/xe: Implement recent spec updates to Wa_16025250150
In reply to Greg Kroah-Hartman6.18-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
@@ -540,6 +540,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 163/309 spi: use generic driver_override infrastructure
In reply to Greg Kroah-Hartman6.18-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 164/309 ACPI: EC: clean up handlers on probe failure in acpi_ec_setup()
In reply to Greg Kroah-Hartman6.18-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 165/309 drm/amdgpu: Fix fence put before wait in amdgpu_amdkfd_submit_ib
In reply to Greg Kroah-Hartman6.18-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 166/309 hwmon: (adm1177) fix sysfs ABI violation and current unit conversion
In reply to Greg Kroah-Hartman6.18-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 167/309 hwmon: (pmbus) Mark lowest/average/highest/rated attributes as read-only
In reply to Greg Kroah-Hartman6.18-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 168/309 hwmon: (pmbus) Introduce the concept of "write-only" attributes
In reply to Greg Kroah-Hartman6.18-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 169/309 hwmon: (pmbus/core) Protect regulator operations with mutex
In reply to Greg Kroah-Hartman6.18-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 170/309 sysctl: fix uninitialized variable in proc_do_large_bitmap
In reply to Greg Kroah-Hartman6.18-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
@@ -1213,7 +1213,7 @@ int proc_do_large_bitmap(const struct ctl_table *table, int write,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 && !write)) { *lenp =0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 171/309 ASoC: adau1372: Fix unchecked clk_prepare_enable() return value
In reply to Greg Kroah-Hartman6.18-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 172/309 ASoC: adau1372: Fix clock leak on PLL lock failure
In reply to Greg Kroah-Hartman6.18-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 173/309 spi: spi-fsl-lpspi: fix teardown order issue (UAF)
In reply to Greg Kroah-Hartman6.18-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 174/309 ALSA: usb-audio: Exclude Scarlett 2i4 1st Gen from SKIP_IFACE_SETUP
In reply to Greg Kroah-Hartman6.18-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
@@ -2423,6 +2423,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 175/309 s390/syscalls: Add spectre boundary for syscall dispatch table
In reply to Greg Kroah-Hartman6.18-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>
@@ -121,8 +122,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 ] = current->thread.sys_call_table[nr](regs); + } out:syscall_exit_to_user_mode (regs); }
Greg Kroah-Hartman
maintainerPATCH 176/309 s390/barrier: Make array_index_mask_nospec() __always_inline
In reply to Greg Kroah-Hartman6.18-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 177/309 s390/entry: Scrub r12 register on kernel entry
In reply to Greg Kroah-Hartman6.18-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
@@ -254,6 +254,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
@@ -390,6 +391,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
@@ -479,6 +481,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 178/309 tracing: Fix potential deadlock in cpu hotplug with osnoise
In reply to Greg Kroah-Hartman6.18-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 179/309 drm/xe: always keep track of remap prev/next
In reply to Greg Kroah-Hartman6.18-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
@@ -1451,9 +1451,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 :
@@ -2038,12 +2038,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;
@@ -2267,10 +2267,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
@@ -2503,7 +2503,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) {
@@ -2513,11 +2512,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;
@@ -2636,6 +2637,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) {
@@ -2783,8 +2786,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
@@ -365,6 +365,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 180/309 ksmbd: replace hardcoded hdr2_len with offsetof() in smb2_calc_max_out_buf_len()
In reply to Greg Kroah-Hartman6.18-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
@@ -4455,8 +4455,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;
@@ -4723,8 +4724,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 ;
@@ -5050,8 +5052,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;
@@ -8192,8 +8195,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 181/309 ksmbd: fix potencial OOB in get_file_all_info() for compound requests
In reply to Greg Kroah-Hartman6.18-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
@@ -4943,7 +4943,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",
@@ -4955,6 +4956,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) {
@@ -4998,7 +5009,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 182/309 ksmbd: fix memory leaks and NULL deref in smb2_lock()
In reply to Greg Kroah-Hartman6.18-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
@@ -7602,14 +7602,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;
@@ -7678,6 +7679,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; } }
@@ -7708,13 +7712,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);
@@ -7724,7 +7732,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 183/309 ksmbd: do not expire session on binding failure
In reply to Greg Kroah-Hartman6.18-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
@@ -1948,8 +1948,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 184/309 Revert "ALSA: hda/intel: Add MSI X870E Tomahawk to denylist"
In reply to Greg Kroah-Hartman6.18-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 185/309 ALSA: hda/realtek: add quirk for ASUS Strix G16 G615JMR
In reply to Greg Kroah-Hartman6.18-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
@@ -7033,6 +7033,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 186/309 ALSA: firewire-lib: fix uninitialized local variable
In reply to Greg Kroah-Hartman6.18-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 187/309 ASoC: codecs: wcd934x: fix typo in dt parsing
In reply to Greg Kroah-Hartman6.18-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_soc_component *comp)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;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 188/309 ASoC: sma1307: fix double free of devm_kzalloc() memory
In reply to Greg Kroah-Hartman6.18-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
@@ -1779,8 +1779,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 189/309 ASoC: SOF: ipc4-topology: Allow bytes controls without initial payload
In reply to Greg Kroah-Hartman6.18-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
@@ -2880,7 +2880,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 190/309 can: gw: fix OOB heap access in cgw_csum_crc8_rel()
In reply to Greg Kroah-Hartman6.18-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 191/309 can: isotp: fix tx.buf use-after-free in isotp_sendmsg()
In reply to Greg Kroah-Hartman6.18-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 192/309 can: netlink: can_changelink(): add missing error handling to call can_ctrlmode_changelink()
In reply to Greg Kroah-Hartman6.18-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
@@ -407,7 +407,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 193/309 cpufreq: conservative: Reset requested_freq on limits change
In reply to Greg Kroah-Hartman6.18-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 194/309 kbuild: Delete .builtin-dtbs.S when running make clean
In reply to Greg Kroah-Hartman6.18-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
@@ -1588,7 +1588,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 195/309 thermal: intel: int340x: soc_slider: Set offset only for balanced mode
In reply to Greg Kroah-Hartman6.18-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,
--- .../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(struct proc_thermal_device *proc_priv, u64 vstatic 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); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 196/309 RDMA/ionic: Preserve and set Ethernet source MAC after ib_ud_header_init()
In reply to Greg Kroah-Hartman6.18-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_ibdev *dev, {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_ibdev *dev, 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_ibdev *dev,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 ) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 197/309 platform/x86: ISST: Correct locked bit width
In reply to Greg Kroah-Hartman6.18-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 198/309 KVM: arm64: Discard PC update state on vcpu reset
In reply to Greg Kroah-Hartman6.18-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 199/309 hwmon: (pmbus/ina233) Fix error handling and sign extension in shunt voltage read
In reply to Greg Kroah-Hartman6.18-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 i2c_client *client, int page,/* 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 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 200/309 hwmon: (pmbus/isl68137) Add mutex protection for AVS enable sysfs attributes
In reply to Greg Kroah-Hartman6.18-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
@@ -94,7 +94,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;
@@ -116,6 +124,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
@@ -127,17 +139,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 201/309 hwmon: (peci/cputemp) Fix crit_hyst returning delta instead of absolute temperature
In reply to Greg Kroah-Hartman6.18-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
@@ -133,7 +133,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 202/309 hwmon: (peci/cputemp) Fix off-by-one in cputemp_is_visible()
In reply to Greg Kroah-Hartman6.18-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
@@ -339,7 +339,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 203/309 media: mc, v4l2: serialize REINIT and REQBUFS with req_queue_mutex
In reply to Greg Kroah-Hartman6.18-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
@@ -3079,13 +3079,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 204/309 xfrm: iptfs: validate inner IPv4 header length in IPTFS payload
In reply to Greg Kroah-Hartman6.18-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 205/309 xfrm: iptfs: only publish mode_data after clone setup
In reply to Greg Kroah-Hartman6.18-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 206/309 virt: tdx-guest: Fix handling of host controlled quote buffer length
In reply to Greg Kroah-Hartman6.18-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 207/309 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.18-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
@@ -3414,6 +3414,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 208/309 erofs: add GFP_NOIO in the bio completion if needed
In reply to Greg Kroah-Hartman6.18-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
@@ -1445,6 +1445,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) {
@@ -1477,7 +1478,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 209/309 alarmtimer: Fix argument order in alarm_timer_forward()
In reply to Greg Kroah-Hartman6.18-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 210/309 writeback: dont block sync for filesystems with no data integrity guarantees
In reply to Greg Kroah-Hartman6.18-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.h | 1 + include/linux/pagemap.h | 11 ----------- 5 files changed, 15 insertions(+), 20 deletions(-)
fs/fs-writeback.c +12 -6
@@ -2735,13 +2735,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);
@@ -2876,6 +2871,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
@@ -3146,10 +3146,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
@@ -1706,6 +1706,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.h +1 -0
@@ -1419,6 +1419,7 @@ extern int send_sigurg(struct file *file#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 */ /* Possible states of 'frozen' field */ enum {
include/linux/pagemap.h +0 -11
@@ -213,7 +213,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,
@@ -349,16 +348,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 211/309 x86/cpu: Enable FSGSBASE early in cpu_init_exception_handling()
In reply to Greg Kroah-Hartman6.18-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
@@ -2020,12 +2020,6 @@ static void identify_cpu(struct cpuinfo_setup_smap (c);setup_umip (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."
@@ -2386,6 +2380,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 212/309 x86/cpu: Remove X86_CR4_FRED from the CR4 pinned bits mask
In reply to Greg Kroah-Hartman6.18-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
@@ -407,7 +407,7 @@ out:/* 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 213/309 x86/fred: Fix early boot failures on SEV-ES/SNP guests
In reply to Greg Kroah-Hartman6.18-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 214/309 phy: qcom: qmp-ufs: Fix SM8650 PCS table for Gear 4
In reply to Greg Kroah-Hartman6.18-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 215/309 ovl: make fsync after metadata copy-up opt-in mount option
In reply to Greg Kroah-Hartman6.18-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
@@ -1159,15 +1159,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:
@@ -634,6 +640,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
@@ -773,7 +773,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 216/309 ovl: fix wrong detection of 32bit inode numbers
In reply to Greg Kroah-Hartman6.18-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
@@ -90,7 +90,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 217/309 scsi: ibmvfc: Fix OOB access in ibmvfc_discover_targets_done()
In reply to Greg Kroah-Hartman6.18-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 218/309 scsi: ses: Handle positive SCSI error from ses_recv_diag()
In reply to Greg Kroah-Hartman6.18-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 219/309 net: macb: Move devm_{free,request}_irq() out of spin lock area
In reply to Greg Kroah-Hartman6.18-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 220/309 net: macb: Protect access to net_device::ip_ptr with RCU lock
In reply to Greg Kroah-Hartman6.18-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->sgmii_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 221/309 net: macb: Use dev_consume_skb_any() to free TX SKBs
In reply to Greg Kroah-Hartman6.18-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
@@ -1108,7 +1108,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 222/309 KVM: x86/mmu: Drop/zap existing present SPTE even when creating an MMIO SPTE
In reply to Greg Kroah-Hartman6.18-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 223/309 KVM: x86/mmu: Only WARN in direct MMUs when overwriting shadow-present SPTE
In reply to Greg Kroah-Hartman6.18-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 *vcpu, struct kvm_memory_slot *slot, 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
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 224/309 jbd2: gracefully abort on checkpointing state corruptions
In reply to Greg Kroah-Hartman6.18-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 225/309 irqchip/qcom-mpm: Add missing mailbox TX done acknowledgment
In reply to Greg Kroah-Hartman6.18-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 226/309 i2c: designware: amdisp: Fix resume-probe race condition issue
In reply to Greg Kroah-Hartman6.18-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 227/309 futex: Clear stale exiting pointer in futex_lock_pi() retry path
In reply to Greg Kroah-Hartman6.18-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 228/309 i2c: imx: fix i2c issue when reading multiple messages
In reply to Greg Kroah-Hartman6.18-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 229/309 i2c: imx: ensure no clock is generated after last read
In reply to Greg Kroah-Hartman6.18-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 230/309 dmaengine: fsl-edma: fix channel parameter config for fixed channel requests
In reply to Greg Kroah-Hartman6.18-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 231/309 dmaengine: sh: rz-dmac: Protect the driver specific lists
In reply to Greg Kroah-Hartman6.18-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 232/309 dmaengine: sh: rz-dmac: Move CHCTRL updates under spinlock
In reply to Greg Kroah-Hartman6.18-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 233/309 drm/amdgpu: prevent immediate PASID reuse case
In reply to Greg Kroah-Hartman6.18-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,
@@ -640,3 +647,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
@@ -2884,6 +2884,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 234/309 drm/amd/display: Fix drm_edid leak in amdgpu_dm
In reply to Greg Kroah-Hartman6.18-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
@@ -3822,8 +3822,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 235/309 drm/i915/dp_tunnel: Fix error handling when clearing stream BW in atomic state
In reply to Greg Kroah-Hartman6.18-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
@@ -4568,6 +4568,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)
@@ -4576,7 +4577,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 236/309 drm/i915: Order OP vs. timeout correctly in __wait_for()
In reply to Greg Kroah-Hartman6.18-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 237/309 drm/i915: Unlink NV12 planes earlier
In reply to Greg Kroah-Hartman6.18-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
@@ -421,11 +421,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);
@@ -1498,6 +1503,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)
@@ -1535,8 +1543,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 238/309 LoongArch: Fix missing NULL checks for kstrdup()
In reply to Greg Kroah-Hartman6.18-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 239/309 LoongArch: vDSO: Emit GNU_EH_FRAME correctly
In reply to Greg Kroah-Hartman6.18-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
@@ -21,7 +21,7 @@ cflags-vdso := $(ccflags-vdso) \ $(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \ -std=gnu11 -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
@@ -36,7 +36,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 240/309 LoongArch: Workaround LS2K/LS7A GPU DMA hang bug
In reply to Greg Kroah-Hartman6.18-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 241/309 LoongArch: KVM: Make kvm_get_vcpu_by_cpuid() more robust
In reply to Greg Kroah-Hartman6.18-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
@@ -561,6 +561,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 242/309 LoongArch: KVM: Handle the case that EIOINTCs coremap is empty
In reply to Greg Kroah-Hartman6.18-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 243/309 drm/amd/pm: Return -EOPNOTSUPP for unsupported OD_MCLK on smu_v13_0_6
In reply to Greg Kroah-Hartman6.18-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
@@ -1494,7 +1494,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 244/309 mm/damon/sysfs: check contexts->nr before accessing contexts_arr[0]
In reply to Greg Kroah-Hartman6.18-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
@@ -1700,6 +1700,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 245/309 mm/damon/sysfs: check contexts->nr in repeat_call_fn
In reply to Greg Kroah-Hartman6.18-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
@@ -1570,9 +1570,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 246/309 mm/pagewalk: fix race between concurrent split and refault
In reply to Greg Kroah-Hartman6.18-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 247/309 xfs: stop reclaim before pushing AIL during unmount
In reply to Greg Kroah-Hartman6.18-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 248/309 xfs: save ailp before dropping the AIL lock in push callbacks
In reply to Greg Kroah-Hartman6.18-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:xfs_dqunlock (dqp);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 249/309 xfs: avoid dereferencing log items after push callbacks
In reply to Greg Kroah-Hartman6.18-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 ;
@@ -1649,16 +1650,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 250/309 xfs: scrub: unlock dquot before early return in quota scrub
In reply to Greg Kroah-Hartman6.18-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
@@ -174,8 +174,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 251/309 xfs: fix ri_total validation in xlog_recover_attri_commit_pass2
In reply to Greg Kroah-Hartman6.18-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 252/309 xfs: dont irele after failing to iget in xfs_attri_recover_work
In reply to Greg Kroah-Hartman6.18-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 253/309 xfs: remove file_path tracepoint data
In reply to Greg Kroah-Hartman6.18-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
@@ -5117,23 +5117,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 254/309 ext4: fix journal credit check when setting fscrypt context
In reply to Greg Kroah-Hartman6.18-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,
Greg Kroah-Hartman
maintainerPATCH 255/309 ext4: convert inline data to extents when truncate exceeds inline size
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Deepanshu Kartikey <[email protected]>
commit ed9356a30e59c7cc3198e7fc46cfedf3767b9b17 upstream.
Add a check in ext4_setattr() to convert files from inline data storage to extent-based storage when truncate() grows the file size beyond the inline capacity. This prevents the filesystem from entering an inconsistent state where the inline data flag is set but the file size exceeds what can be stored inline.
Without this fix, the following sequence causes a kernel BUG_ON():
1. Mount filesystem with inode that has inline flag set and small size
2. truncate(file, 50MB) - grows size but inline flag remains set
3. sendfile() attempts to write data
4. ext4_write_inline_data() hits BUG_ON(write_size > inline_capacity)
The crash occurs because ext4_write_inline_data() expects inline storage to accommodate the write, but the actual inline capacity (~60 bytes for i_block + ~96 bytes for xattrs) is far smaller than the file size and write request.
The fix checks if the new size from setattr exceeds the inode's actual inline capacity (EXT4_I(inode)->i_inline_size) and converts the file to extent-based storage before proceeding with the size change.
This addresses the root cause by ensuring the inline data flag and file size remain consistent during truncate operations.
--- fs/ext4/inode.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
fs/ext4/inode.c +12 -0
@@ -5915,6 +5915,18 @@ int ext4_setattr(struct mnt_idmap *idmapif (attr->ia_size == inode->i_size) inc_ivers = false; +/* +* If file has inline data but new size exceeds inline capacity, +* convert to extent-based storage first to prevent inconsistent +* state (inline flag set but size exceeds inline capacity). +*/ +if (ext4_has_inline_data (inode) && + attr->ia_size >EXT4_I (inode)->i_inline_size) { + error =ext4_convert_inline_data (inode); +if (error) + goto err_out; + } +if (shrink) {if (ext4_should_order_data (inode)) { error = ext4_begin_ordered_truncate(inode,
Greg Kroah-Hartman
maintainerPATCH 256/309 ext4: fix stale xarray tags after writeback
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jan Kara <[email protected]>
commit f4a2b42e78914ff15630e71289adc589c3a8eb45 upstream.
There are cases where ext4_bio_write_page() gets called for a page which has no buffers to submit. This happens e.g. when the part of the file is actually a hole, when we cannot allocate blocks due to being called from jbd2, or in data=journal mode when checkpointing writes the buffers earlier. In these cases we just return from ext4_bio_write_page() however if the page didn't need redirtying, we will leave stale DIRTY and/or TOWRITE tags in xarray because those get cleared only in __folio_start_writeback(). As a result we can leave these tags set in mappings even after a final sync on filesystem that's getting remounted read-only or that's being frozen. Various assertions can then get upset when writeback is started on such filesystems (Gerald reported assertion in ext4_journal_check_start() firing).
Fix the problem by cycling the page through writeback state even if we decide nothing needs to be written for it so that xarray tags get properly updated. This is slightly silly (we could update the xarray tags directly) but I don't think a special helper messing with xarray tags is really worth it in this relatively rare corner case.
--- fs/ext4/page-io.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
fs/ext4/page-io.c +8 -2
@@ -523,9 +523,15 @@ int ext4_bio_write_folio(struct ext4_io_ nr_to_submit++; }while ((bh = bh->b_this_page) != head); -/* Nothing to submit? Just unlock the folio... */ -if (!nr_to_submit) +if (!nr_to_submit) { +/* +* We have nothing to submit. Just cycle the folio through +* writeback state to properly update xarray tags. +*/ +__folio_start_writeback (folio, keep_towrite); +folio_end_writeback (folio);return 0 ; + } bh = head =folio_buffers (folio);
Greg Kroah-Hartman
maintainerPATCH 257/309 ext4: do not check fast symlink during orphan recovery
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhang Yi <[email protected]>
commit 84e21e3fb8fd99ea460eb7274584750d11cf3e9f upstream.
Commit '5f920d5d6083 ("ext4: verify fast symlink length")' causes the generic/475 test to fail during orphan cleanup of zero-length symlinks.
generic/475 84s ... _check_generic_filesystem: filesystem on /dev/vde is inconsistent
The fsck reports are provided below:
Deleted inode 9686 has zero dtime.
Deleted inode 158230 has zero dtime.
...
Inode bitmap differences: -9686 -158230
Orphan file (inode 12) block 13 is not clean.
Failed to initialize orphan file.
In ext4_symlink(), a newly created symlink can be added to the orphan list due to ENOSPC. Its data has not been initialized, and its size is zero. Therefore, we need to disregard the length check of the symbolic link when cleaning up orphan inodes. Instead, we should ensure that the nlink count is zero.
--- fs/ext4/inode.c | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-)
fs/ext4/inode.c +29 -11
@@ -5465,18 +5465,36 @@ struct inode *__ext4_iget(struct super_b inode->i_op = &ext4_encrypted_symlink_inode_operations; }else if (ext4_inode_is_fast_symlink (inode)) { inode->i_op = &ext4_fast_symlink_inode_operations; -if (inode->i_size ==0 || - inode->i_size >=sizeof (ei->i_data) || -strnlen ((char *)ei->i_data, inode->i_size +1 ) != - inode->i_size) { -ext4_error_inode (inode, function, line,0 , -"invalid fast symlink length %llu" , - (unsigned long long )inode->i_size); - ret = -EFSCORRUPTED ; - goto bad_inode; + +/* +* Orphan cleanup can see inodes with i_size == 0 +* and i_data uninitialized. Skip size checks in +* that case. This is safe because the first thing +* ext4_evict_inode() does for fast symlinks is +* clearing of i_data and i_size. +*/ +if ((EXT4_SB (sb)->s_mount_state &EXT4_ORPHAN_FS )) { +if (inode->i_nlink !=0 ) { +ext4_error_inode (inode, function, line,0 , +"invalid orphan symlink nlink %d" , + inode->i_nlink); + ret = -EFSCORRUPTED ; + goto bad_inode; + } + }else { +if (inode->i_size ==0 || + inode->i_size >=sizeof (ei->i_data) || +strnlen ((char *)ei->i_data, inode->i_size +1 ) != + inode->i_size) { +ext4_error_inode (inode, function, line,0 , +"invalid fast symlink length %llu" , + (unsigned long long )inode->i_size); + ret = -EFSCORRUPTED ; + goto bad_inode; + } +inode_set_cached_link (inode, (char *)ei->i_data, + inode->i_size); } -inode_set_cached_link (inode, (char *)ei->i_data, - inode->i_size); }else { inode->i_op = &ext4_symlink_inode_operations; }
Greg Kroah-Hartman
maintainerPATCH 258/309 ext4: fix fsync(2) for nojournal mode
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jan Kara <[email protected]>
commit 1308255bbf8452762f89f44f7447ce137ecdbcff upstream.
When inode metadata is changed, we sometimes just call ext4_mark_inode_dirty() to track modified metadata. This copies inode metadata into block buffer which is enough when we are journalling metadata. However when we are running in nojournal mode we currently fail to write the dirtied inode buffer during fsync(2) because the inode is not marked as dirty. Use explicit ext4_write_inode() call to make sure the inode table buffer is written to the disk. This is a band aid solution but proper solution requires a much larger rewrite including changes in metadata bh tracking infrastructure.
--- fs/ext4/fsync.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-)
fs/ext4/fsync.c +14 -2
@@ -83,11 +83,23 @@ static int ext4_fsync_nojournal(struct f int datasync, bool *needs_barrier) { struct inode *inode = file->f_inode; +struct writeback_control wbc = { + .sync_mode =WB_SYNC_ALL , + .nr_to_write =0 , + };int ret; ret =generic_buffers_fsync_noflush (file, start, end, datasync); -if (!ret) - ret =ext4_sync_parent (inode); +if (ret) +return ret; + +/* Force writeout of inode table buffer to disk */ + ret =ext4_write_inode (inode, &wbc); +if (ret) +return ret; + + ret =ext4_sync_parent (inode); +if (test_opt (inode->i_sb,BARRIER )) *needs_barrier = true;
Greg Kroah-Hartman
maintainerPATCH 259/309 ext4: make recently_deleted() properly work with lazy itable initialization
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jan Kara <[email protected]>
commit bd060afa7cc3e0ad30afa9ecc544a78638498555 upstream.
recently_deleted() checks whether inode has been used in the near past. However this can give false positive result when inode table is not initialized yet and we are in fact comparing to random garbage (or stale itable block of a filesystem before mkfs). Ultimately this results in uninitialized inodes being skipped during inode allocation and possibly they are never initialized and thus e2fsck complains. Verify if the inode has been initialized before checking for dtime.
--- fs/ext4/ialloc.c | 6 ++++++ 1 file changed, 6 insertions(+)
fs/ext4/ialloc.c +6 -0
@@ -686,6 +686,12 @@ static int recently_deleted(struct superif (unlikely (!gdp))return 0 ; +/* Inode was never used in this filesystem? */ +if (ext4_has_group_desc_csum (sb) && + (gdp->bg_flags &cpu_to_le16 (EXT4_BG_INODE_UNINIT ) || + ino >=EXT4_INODES_PER_GROUP (sb) -ext4_itable_unused_count (sb, gdp))) +return 0 ; + bh =sb_find_get_block (sb,ext4_inode_table (sb, gdp) + (ino / inodes_per_block));if (!bh || !buffer_uptodate (bh))
Greg Kroah-Hartman
maintainerPATCH 260/309 ext4: replace BUG_ON with proper error handling in ext4_read_inline_folio
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuto Ohnuki <[email protected]>
commit 356227096eb66e41b23caf7045e6304877322edf upstream.
Replace BUG_ON() with proper error handling when inline data size exceeds PAGE_SIZE. This prevents kernel panic and allows the system to continue running while properly reporting the filesystem corruption.
The error is logged via ext4_error_inode(), the buffer head is released to prevent memory leak, and -EFSCORRUPTED is returned to indicate filesystem corruption.
--- fs/ext4/inline.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
fs/ext4/inline.c +9 -1
@@ -522,7 +522,15 @@ static int ext4_read_inline_folio(struct goto out; len =min_t (size_t,ext4_get_inline_size (inode),i_size_read (inode)); -BUG_ON (len >PAGE_SIZE ); + +if (len >PAGE_SIZE ) { +ext4_error_inode (inode, __func__, __LINE__,0 , +"inline size %zu exceeds PAGE_SIZE" , len); + ret = -EFSCORRUPTED ; +brelse (iloc.bh); + goto out; + } + kaddr =kmap_local_folio (folio,0 ); ret =ext4_read_inline_data (inode, kaddr, len, &iloc); kaddr =folio_zero_tail (folio, len, kaddr + len);
Greg Kroah-Hartman
maintainerPATCH 261/309 ext4: publish jinode after initialization
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Li Chen <[email protected]>
commit 1aec30021edd410b986c156f195f3d23959a9d11 upstream.
ext4_inode_attach_jinode() publishes ei->jinode to concurrent users. It used to set ei->jinode before jbd2_journal_init_jbd_inode(), allowing a reader to observe a non-NULL jinode with i_vfs_inode still unset.
The fast commit flush path can then pass this jinode to jbd2_wait_inode_data(), which dereferences i_vfs_inode->i_mapping and may crash.
Below is the crash I observe:
``` BUG: unable to handle page fault for address: 000000010beb47f4 PGD 110e51067 P4D 110e51067 PUD 0 Oops: Oops: 0000 [#1] SMP NOPTI CPU: 1 UID: 0 PID: 4850 Comm: fc_fsync_bench_ Not tainted 6.18.0-00764-g795a690c06a5 #1 PREEMPT(voluntary) Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Arch Linux 1.17.0-2-2 04/01/2014 RIP: 0010:xas_find_marked+0x3d/0x2e0 Code: e0 03 48 83 f8 02 0f 84 f0 01 00 00 48 8b 47 08 48 89 c3 48 39 c6 0f 82 fd 01 00 00 48 85 c9 74 3d 48 83 f9 03 77 63 4c 8b 0f <49> 8b 71 08 48 c7 47 18 00 00 00 00 48 89 f1 83 e1 03 48 83 f9 02 RSP: 0018:ffffbbee806e7bf0 EFLAGS: 00010246 RAX: 000000000010beb4 RBX: 000000000010beb4 RCX: 0000000000000003 RDX: 0000000000000001 RSI: 0000002000300000 RDI: ffffbbee806e7c10 RBP: 0000000000000001 R08: 0000002000300000 R09: 000000010beb47ec R10: ffff9ea494590090 R11: 0000000000000000 R12: 0000002000300000 R13: ffffbbee806e7c90 R14: ffff9ea494513788 R15: ffffbbee806e7c88 FS: 00007fc2f9e3e6c0(0000) GS:ffff9ea6b1444000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000000010beb47f4 CR3: 0000000119ac5000 CR4: 0000000000750ef0 PKRU: 55555554 Call Trace: <TASK> filemap_get_folios_tag+0x87/0x2a0 __filemap_fdatawait_range+0x5f/0xd0 ? srso_alias_return_thunk+0x5/0xfbef5 ? __schedule+0x3e7/0x10c0 ? srso_alias_return_thunk+0x5/0xfbef5 ? srso_alias_return_thunk+0x5/0xfbef5 ? srso_alias_return_thunk+0x5/0xfbef5 ? preempt_count_sub+0x5f/0x80 ? srso_alias_return_thunk+0x5/0xfbef5 ? cap_safe_nice+0x37/0x70 ? srso_alias_return_thunk+0x5/0xfbef5 ? preempt_count_sub+0x5f/0x80 ? srso_alias_return_thunk+0x5/0xfbef5 filemap_fdatawait_range_keep_errors+0x12/0x40 ext4_fc_commit+0x697/0x8b0 ? ext4_file_write_iter+0x64b/0x950 ? srso_alias_return_thunk+0x5/0xfbef5 ? preempt_count_sub+0x5f/0x80 ? srso_alias_return_thunk+0x5/0xfbef5 ? vfs_write+0x356/0x480 ? srso_alias_return_thunk+0x5/0xfbef5 ? preempt_count_sub+0x5f/0x80 ext4_sync_file+0xf7/0x370 do_fsync+0x3b/0x80 ? syscall_trace_enter+0x108/0x1d0 __x64_sys_fdatasync+0x16/0x20 do_syscall_64+0x62/0x2c0 entry_SYSCALL_64_after_hwframe+0x76/0x7e ... ```
Fix this by initializing the jbd2_inode first.
Use smp_wmb() and WRITE_ONCE() to publish ei->jinode after initialization. Readers use READ_ONCE() to fetch the pointer.
--- fs/ext4/fast_commit.c | 4 ++-- fs/ext4/inode.c | 15 +++++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-)
fs/ext4/fast_commit.c +2 -2
@@ -975,13 +975,13 @@ static int ext4_fc_flush_data(journal_tint ret =0 ;list_for_each_entry (ei, &sbi->s_fc_q[FC_Q_MAIN ], i_fc_list) { - ret =jbd2_submit_inode_data (journal, ei->jinode); + ret =jbd2_submit_inode_data (journal,READ_ONCE (ei->jinode));if (ret)return ret; }list_for_each_entry (ei, &sbi->s_fc_q[FC_Q_MAIN ], i_fc_list) { - ret =jbd2_wait_inode_data (journal, ei->jinode); + ret =jbd2_wait_inode_data (journal,READ_ONCE (ei->jinode));if (ret)return ret; }
fs/ext4/inode.c +11 -4
@@ -126,6 +126,8 @@ void ext4_inode_csum_set(struct inode *istatic inline int ext4_begin_ordered_truncate (struct inode *inode,loff_t new_size) { +struct jbd2_inode *jinode =READ_ONCE (EXT4_I (inode)->jinode); +trace_ext4_begin_ordered_truncate (inode, new_size);/* * If jinode is zero, then we never opened the file for
@@ -133,10 +135,10 @@ static inline int ext4_begin_ordered_tru* jbd2_journal_begin_ordered_truncate() since there's no * outstanding writes we need to flush. */ -if (!EXT4_I (inode)->jinode) +if (!jinode)return 0 ;return jbd2_journal_begin_ordered_truncate (EXT4_JOURNAL (inode), -EXT4_I (inode)->jinode, + jinode, new_size); }
@@ -4501,8 +4503,13 @@ int ext4_inode_attach_jinode(struct inodspin_unlock (&inode->i_lock);return -ENOMEM ; } - ei->jinode = jinode; -jbd2_journal_init_jbd_inode (ei->jinode, inode); +jbd2_journal_init_jbd_inode (jinode, inode); +/* +* Publish ->jinode only after it is fully initialized so that +* readers never observe a partially initialized jbd2_inode. +*/ +smp_wmb (); +WRITE_ONCE (ei->jinode, jinode); jinode =NULL ; }spin_unlock (&inode->i_lock);
Greg Kroah-Hartman
maintainerPATCH 262/309 ext4: test if inodes all dirty pages are submitted to disk
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ye Bin <[email protected]>
commit 73bf12adbea10b13647864cd1c62410d19e21086 upstream.
The commit aa373cf55099 ("writeback: stop background/kupdate works from livelocking other works") introduced an issue where unmounting a filesystem in a multi-logical-partition scenario could lead to batch file data loss. This problem was not fixed until the commit d92109891f21 ("fs/writeback:
bail out if there is no more inodes for IO and queued once"). It took considerable time to identify the root cause. Additionally, in actual production environments, we frequently encountered file data loss after normal system reboots. Therefore, we are adding a check in the inode release flow to verify whether all dirty pages have been flushed to disk, in order to determine whether the data loss is caused by a logic issue in the filesystem code.
--- fs/ext4/inode.c | 8 ++++++++ 1 file changed, 8 insertions(+)
fs/ext4/inode.c +8 -0
@@ -184,6 +184,14 @@ void ext4_evict_inode(struct inode *inodif (EXT4_I (inode)->i_flags &EXT4_EA_INODE_FL )ext4_evict_ea_inode (inode);if (inode->i_nlink) { +/* +* If there's dirty page will lead to data loss, user +* could see stale data. +*/ +if (unlikely (!ext4_emergency_state (inode->i_sb) && +mapping_tagged (&inode->i_data,PAGECACHE_TAG_DIRTY ))) +ext4_warning_inode (inode,"data will be lost" ); +truncate_inode_pages_final (&inode->i_data); goto no_delete;
Greg Kroah-Hartman
maintainerPATCH 263/309 ext4: validate p_idx bounds in ext4_ext_correct_indexes
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tejas Bharambe <[email protected]>
commit 2acb5c12ebd860f30e4faf67e6cc8c44ddfe5fe8 upstream.
ext4_ext_correct_indexes() walks up the extent tree correcting index entries when the first extent in a leaf is modified. Before accessing path[k].p_idx->ei_block, there is no validation that p_idx falls within the valid range of index entries for that level.
If the on-disk extent header contains a corrupted or crafted eh_entries value, p_idx can point past the end of the allocated buffer, causing a slab-out-of-bounds read.
Fix this by validating path[k].p_idx against EXT_LAST_INDEX() at both access sites: before the while loop and inside it. Return -EFSCORRUPTED if the index pointer is out of range, consistent with how other bounds violations are handled in the ext4 extent tree code.
--- fs/ext4/extents.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
fs/ext4/extents.c +15 -0
@@ -1741,6 +1741,13 @@ static int ext4_ext_correct_indexes(hand err =ext4_ext_get_access (handle, inode, path + k);if (err)return err; +if (unlikely (path[k].p_idx >EXT_LAST_INDEX (path[k].p_hdr))) { +EXT4_ERROR_INODE (inode, +"path[%d].p_idx %p > EXT_LAST_INDEX %p" , + k, path[k].p_idx, +EXT_LAST_INDEX (path[k].p_hdr)); +return -EFSCORRUPTED ; + } path[k].p_idx->ei_block = border; err =ext4_ext_dirty (handle, inode, path + k);if (err)
@@ -1753,6 +1760,14 @@ static int ext4_ext_correct_indexes(hand err =ext4_ext_get_access (handle, inode, path + k);if (err) goto clean; +if (unlikely (path[k].p_idx >EXT_LAST_INDEX (path[k].p_hdr))) { +EXT4_ERROR_INODE (inode, +"path[%d].p_idx %p > EXT_LAST_INDEX %p" , + k, path[k].p_idx, +EXT_LAST_INDEX (path[k].p_hdr)); + err = -EFSCORRUPTED ; + goto clean; + } path[k].p_idx->ei_block = border; err =ext4_ext_dirty (handle, inode, path + k);if (err)
Greg Kroah-Hartman
maintainerPATCH 264/309 ext4: avoid infinite loops caused by residual data
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Edward Adam Davis <[email protected]>
commit 5422fe71d26d42af6c454ca9527faaad4e677d6c upstream.
On the mkdir/mknod path, when mapping logical blocks to physical blocks, if inserting a new extent into the extent tree fails (in this example, because the file system disabled the huge file feature when marking the inode as dirty), ext4_ext_map_blocks() only calls ext4_free_blocks() to reclaim the physical block without deleting the corresponding data in the extent tree. This causes subsequent mkdir operations to reference the previously reclaimed physical block number again, even though this physical block is already being used by the xattr block. Therefore, a situation arises where both the directory and xattr are using the same buffer head block in memory simultaneously.
The above causes ext4_xattr_block_set() to enter an infinite loop about "inserted" and cannot release the inode lock, ultimately leading to the 143s blocking problem mentioned in [1].
If the metadata is corrupted, then trying to remove some extent space can do even more harm. Also in case EXT4_GET_BLOCKS_DELALLOC_RESERVE was passed, remove space wrongly update quota information. Jan Kara suggests distinguishing between two cases:
1) The error is ENOSPC or EDQUOT - in this case the filesystem is fully consistent and we must maintain its consistency including all the accounting. However these errors can happen only early before we've inserted the extent into the extent tree. So current code works correctly for this case.
2) Some other error - this means metadata is corrupted. We should strive to do as few modifications as possible to limit damage. So I'd just skip freeing of allocated blocks.
[1]
INFO: task syz.0.17:5995 blocked for more than 143 seconds. Call Trace: inode_lock_nested include/linux/fs.h:1073 [inline] __start_dirop fs/namei.c:2923 [inline] start_dirop fs/namei.c:2934 [inline]
--- fs/ext4/extents.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
fs/ext4/extents.c +6 -2
@@ -4461,9 +4461,13 @@ got_allocated_blocks: path =ext4_ext_insert_extent (handle, inode, path, &newex, flags);if (IS_ERR (path)) { err =PTR_ERR (path); -if (allocated_clusters) { +/* +* Gracefully handle out of space conditions. If the filesystem +* is inconsistent, we'll just leak allocated blocks to avoid +* causing even more damage. +*/ +if (allocated_clusters && (err == -EDQUOT || err == -ENOSPC )) {int fb_flags =0 ; -/* * free data blocks we just allocated. * not a good idea to call discard here directly,
Greg Kroah-Hartman
maintainerPATCH 265/309 ext4: avoid allocate block from corrupted group in ext4_mb_find_by_goal()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ye Bin <[email protected]>
commit 46066e3a06647c5b186cc6334409722622d05c44 upstream.
There's issue as follows:
...
EXT4-fs (mmcblk0p1): Delayed block allocation failed for inode 206 at logical offset 0 with max blocks 1 with error 117 EXT4-fs (mmcblk0p1): This should not happen!! Data will be lost
EXT4-fs (mmcblk0p1): Delayed block allocation failed for inode 206 at logical offset 0 with max blocks 1 with error 117 EXT4-fs (mmcblk0p1): This should not happen!! Data will be lost
EXT4-fs (mmcblk0p1): Delayed block allocation failed for inode 206 at logical offset 0 with max blocks 1 with error 117 EXT4-fs (mmcblk0p1): This should not happen!! Data will be lost
EXT4-fs (mmcblk0p1): Delayed block allocation failed for inode 206 at logical offset 0 with max blocks 1 with error 117 EXT4-fs (mmcblk0p1): This should not happen!! Data will be lost
EXT4-fs (mmcblk0p1): Delayed block allocation failed for inode 2243 at logical offset 0 with max blocks 1 with error 117 EXT4-fs (mmcblk0p1): This should not happen!! Data will be lost
EXT4-fs (mmcblk0p1): Delayed block allocation failed for inode 2239 at logical offset 0 with max blocks 1 with error 117 EXT4-fs (mmcblk0p1): This should not happen!! Data will be lost
EXT4-fs (mmcblk0p1): error count since last fsck: 1
EXT4-fs (mmcblk0p1): initial error at time 1765597433: ext4_mb_generate_buddy:760 EXT4-fs (mmcblk0p1): last error at time 1765597433: ext4_mb_generate_buddy:760
...
According to the log analysis, blocks are always requested from the corrupted block group. This may happen as follows:ext4_mb_find_by_goal
ext4_mb_load_buddy
ext4_mb_load_buddy_gfp
ext4_mb_init_cache
ext4_read_block_bitmap_nowait
ext4_wait_block_bitmap
ext4_validate_block_bitmap
if (!grp || EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
return -EFSCORRUPTED; // There's no logs.
if (err)
return err; // Will return errorext4_lock_group(ac->ac_sb, group);
if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(e4b->bd_info))) // Unreachable
goto out;
After commit 9008a58e5dce ("ext4: make the bitmap read routines return real error codes") merged, Commit 163a203ddb36 ("ext4: mark block group as corrupt on block bitmap error") is no real solution for allocating blocks from corrupted block groups. This is because if 'EXT4_MB_GRP_BBITMAP_CORRUPT(e4b->bd_info)' is true, then 'ext4_mb_load_buddy()' may return an error. This means that the block allocation will fail.
Therefore, check block group if corrupted when ext4_mb_load_buddy() returns error.
--- fs/ext4/mballoc.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
fs/ext4/mballoc.c +5 -1
@@ -2440,8 +2440,12 @@ int ext4_mb_find_by_goal(struct ext4_allreturn 0 ; err =ext4_mb_load_buddy (ac->ac_sb, group, e4b); -if (err) +if (err) { +if (EXT4_MB_GRP_BBITMAP_CORRUPT (e4b->bd_info) && + !(ac->ac_flags &EXT4_MB_HINT_GOAL_ONLY )) +return 0 ;return err; + }ext4_lock_group (ac->ac_sb, group);if (unlikely (EXT4_MB_GRP_BBITMAP_CORRUPT (e4b->bd_info)))
Greg Kroah-Hartman
maintainerPATCH 266/309 ext4: reject mount if bigalloc with s_first_data_block != 0
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Helen Koike <[email protected]>
commit 3822743dc20386d9897e999dbb990befa3a5b3f8 upstream.
bigalloc with s_first_data_block != 0 is not supported, reject mounting it.
--- fs/ext4/super.c | 7 +++++++ 1 file changed, 7 insertions(+)
fs/ext4/super.c +7 -0
@@ -3624,6 +3624,13 @@ int ext4_feature_set_ok(struct super_blo "extents feature\n");return 0 ; } +if (ext4_has_feature_bigalloc (sb) && +le32_to_cpu (EXT4_SB (sb)->s_es->s_first_data_block)) { +ext4_msg (sb,KERN_WARNING , +"bad geometry: bigalloc file system with non-zero " +"first_data_block\n" ); +return 0 ; + }#if !IS_ENABLED (CONFIG_QUOTA ) || !IS_ENABLED (CONFIG_QFMT_V2 ) if (!readonly && (ext4_has_feature_quota(sb) ||
Greg Kroah-Hartman
maintainerPATCH 267/309 ext4: fix use-after-free in update_super_work when racing with umount
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiayuan Chen <[email protected]>
commit d15e4b0a418537aafa56b2cb80d44add83e83697 upstream.
Commit b98535d09179 ("ext4: fix bug_on in start_this_handle during umount filesystem") moved ext4_unregister_sysfs() before flushing s_sb_upd_work to prevent new error work from being queued via /proc/fs/ext4/xx/mb_groups reads during unmount. However, this introduced a use-after-free because update_super_work calls ext4_notify_error_sysfs() -> sysfs_notify() which accesses the kobject's kernfs_node after it has been freed by kobject_del() in ext4_unregister_sysfs():
update_super_work ext4_put_super
----------------- --------------
ext4_unregister_sysfs(sb)
kobject_del(&sbi->s_kobj)
__kobject_del()
sysfs_remove_dir()
kobj->sd = NULL
sysfs_put(sd)
kernfs_put() // RCU free
ext4_notify_error_sysfs(sbi)
sysfs_notify(&sbi->s_kobj)
kn = kobj->sd // stale pointer
kernfs_get(kn) // UAF on freed kernfs_node
ext4_journal_destroy()
flush_work(&sbi->s_sb_upd_work)Instead of reordering the teardown sequence, fix this by making ext4_notify_error_sysfs() detect that sysfs has already been torn down by checking s_kobj.state_in_sysfs, and skipping the sysfs_notify() call in that case. A dedicated mutex (s_error_notify_mutex) serializes ext4_notify_error_sysfs() against kobject_del() in ext4_unregister_sysfs() to prevent TOCTOU races where the kobject could be deleted between the state_in_sysfs check and the sysfs_notify() call.
--- fs/ext4/ext4.h | 1 + fs/ext4/super.c | 1 + fs/ext4/sysfs.c | 10 +++++++++- 3 files changed, 11 insertions(+), 1 deletion(-)
fs/ext4/ext4.h +1 -0
@@ -1564,6 +1564,7 @@ struct ext4_sb_info {struct proc_dir_entry *s_proc;struct kobject s_kobj;struct completion s_kobj_unregister; +struct mutex s_error_notify_mutex;/* protects sysfs_notify vs kobject_del */ struct super_block *s_sb;struct buffer_head *s_mmp_bh;
fs/ext4/super.c +1 -0
@@ -5361,6 +5361,7 @@ static int __ext4_fill_super(struct fs_ctimer_setup (&sbi->s_err_report, print_daily_error_info,0 );spin_lock_init (&sbi->s_error_lock); +mutex_init (&sbi->s_error_notify_mutex);INIT_WORK (&sbi->s_sb_upd_work, update_super_work); err =ext4_group_desc_init (sb, es, logical_sb_block, &first_not_zeroed);
fs/ext4/sysfs.c +9 -1
@@ -555,7 +555,10 @@ static const struct kobj_type ext4_feat_void ext4_notify_error_sysfs (struct ext4_sb_info *sbi) { -sysfs_notify (&sbi->s_kobj,NULL ,"errors_count" ); +mutex_lock (&sbi->s_error_notify_mutex); +if (sbi->s_kobj.state_in_sysfs) +sysfs_notify (&sbi->s_kobj,NULL ,"errors_count" ); +mutex_unlock (&sbi->s_error_notify_mutex); }static struct kobject *ext4_root;
@@ -568,8 +571,10 @@ int ext4_register_sysfs(struct super_bloint err;init_completion (&sbi->s_kobj_unregister); +mutex_lock (&sbi->s_error_notify_mutex); err =kobject_init_and_add (&sbi->s_kobj, &ext4_sb_ktype, ext4_root,"%s" , sb->s_id); +mutex_unlock (&sbi->s_error_notify_mutex);if (err) {kobject_put (&sbi->s_kobj);wait_for_completion (&sbi->s_kobj_unregister);
@@ -602,7 +607,10 @@ void ext4_unregister_sysfs(struct super_if (sbi->s_proc)remove_proc_subtree (sb->s_id, ext4_proc_root); + +mutex_lock (&sbi->s_error_notify_mutex);kobject_del (&sbi->s_kobj); +mutex_unlock (&sbi->s_error_notify_mutex); }int __init ext4_init_sysfs (void )
Greg Kroah-Hartman
maintainerPATCH 268/309 ext4: fix the might_sleep() warnings in kvfree()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zqiang <[email protected]>
commit 496bb99b7e66f48b178126626f47e9ba79e2d0fa upstream.
Use the kvfree() in the RCU read critical section can trigger the following warnings:
EXT4-fs (vdb): unmounting filesystem cd983e5b-3c83-4f5a-a136-17b00eb9d018.
WARNING: suspicious RCU usage
./include/linux/rcupdate.h:409 Illegal context switch in RCU read-side critical section!
other info that might help us debug this:
rcu_scheduler_active = 2, debug_locks = 1
Call Trace: <TASK> dump_stack_lvl+0xbb/0xd0 dump_stack+0x14/0x20 lockdep_rcu_suspicious+0x15a/0x1b0 __might_resched+0x375/0x4d0 ? put_object.part.0+0x2c/0x50 __might_sleep+0x108/0x160 vfree+0x58/0x910 ? ext4_group_desc_free+0x27/0x270 kvfree+0x23/0x40 ext4_group_desc_free+0x111/0x270 ext4_put_super+0x3c8/0xd40 generic_shutdown_super+0x14c/0x4a0 ? __pfx_shrinker_free+0x10/0x10 kill_block_super+0x40/0x90 ext4_kill_sb+0x6d/0xb0 deactivate_locked_super+0xb4/0x180 deactivate_super+0x7e/0xa0 cleanup_mnt+0x296/0x3e0 __cleanup_mnt+0x16/0x20 task_work_run+0x157/0x250 ? __pfx_task_work_run+0x10/0x10 ? exit_to_user_mode_loop+0x6a/0x550 exit_to_user_mode_loop+0x102/0x550 do_syscall_64+0x44a/0x500 entry_SYSCALL_64_after_hwframe+0x77/0x7f </TASK> BUG: sleeping function called from invalid context at mm/vmalloc.c:3441 in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 556, name: umount preempt_count: 1, expected: 0 CPU: 3 UID: 0 PID: 556 Comm: umount Call Trace: <TASK> dump_stack_lvl+0xbb/0xd0 dump_stack+0x14/0x20 __might_resched+0x275/0x4d0 ? put_object.part.0+0x2c/0x50 __might_sleep+0x108/0x160 vfree+0x58/0x910 ? ext4_group_desc_free+0x27/0x270 kvfree+0x23/0x40 ext4_group_desc_free+0x111/0x270 ext4_put_super+0x3c8/0xd40 generic_shutdown_super+0x14c/0x4a0 ? __pfx_shrinker_free+0x10/0x10 kill_block_super+0x40/0x90 ext4_kill_sb+0x6d/0xb0 deactivate_locked_super+0xb4/0x180 deactivate_super+0x7e/0xa0 cleanup_mnt+0x296/0x3e0 __cleanup_mnt+0x16/0x20 task_work_run+0x157/0x250 ? __pfx_task_work_run+0x10/0x10 ? exit_to_user_mode_loop+0x6a/0x550 exit_to_user_mode_loop+0x102/0x550 do_syscall_64+0x44a/0x500 entry_SYSCALL_64_after_hwframe+0x77/0x7f
The above scenarios occur in initialization failures and teardown paths, there are no parallel operations on the resources released by kvfree(), this commit therefore remove rcu_read_lock/unlock() and use rcu_access_pointer() instead of rcu_dereference() operations.
--- fs/ext4/mballoc.c | 10 +++------- fs/ext4/super.c | 8 ++------ 2 files changed, 5 insertions(+), 13 deletions(-)
fs/ext4/mballoc.c +3 -7
@@ -3579,9 +3579,7 @@ err_freebuddy:rcu_read_unlock ();iput (sbi->s_buddy_cache); err_freesgi: -rcu_read_lock (); -kvfree (rcu_dereference (sbi->s_group_info)); -rcu_read_unlock (); +kvfree (rcu_access_pointer (sbi->s_group_info));return -ENOMEM ; }
@@ -3898,7 +3896,8 @@ void ext4_mb_release(struct super_blockWARN_ON_ONCE (!list_empty (&sbi->s_discard_list)); } -if (sbi->s_group_info) { + group_info =rcu_access_pointer (sbi->s_group_info); +if (group_info) {for (i =0 ; i < ngroups; i++) {cond_resched (); grinfo =ext4_get_group_info (sb, i);
@@ -3916,12 +3915,9 @@ void ext4_mb_release(struct super_block num_meta_group_infos = (ngroups +EXT4_DESC_PER_BLOCK (sb) -1 ) >>EXT4_DESC_PER_BLOCK_BITS (sb); -rcu_read_lock (); - group_info =rcu_dereference (sbi->s_group_info);for (i =0 ; i < num_meta_group_infos; i++)kfree (group_info[i]);kvfree (group_info); -rcu_read_unlock (); }ext4_mb_avg_fragment_size_destroy (sbi);ext4_mb_largest_free_orders_destroy (sbi);
fs/ext4/super.c +2 -6
@@ -1249,12 +1249,10 @@ static void ext4_group_desc_free(structstruct buffer_head **group_desc;int i; -rcu_read_lock (); - group_desc =rcu_dereference (sbi->s_group_desc); + group_desc =rcu_access_pointer (sbi->s_group_desc);for (i =0 ; i < sbi->s_gdb_count; i++)brelse (group_desc[i]);kvfree (group_desc); -rcu_read_unlock (); }static void ext4_flex_groups_free (struct ext4_sb_info *sbi)
@@ -1262,14 +1260,12 @@ static void ext4_flex_groups_free(structstruct flex_groups **flex_groups;int i; -rcu_read_lock (); - flex_groups =rcu_dereference (sbi->s_flex_groups); + flex_groups =rcu_access_pointer (sbi->s_flex_groups);if (flex_groups) {for (i =0 ; i < sbi->s_flex_groups_allocated; i++)kvfree (flex_groups[i]);kvfree (flex_groups); } -rcu_read_unlock (); }static void ext4_put_super (struct super_block *sb)
Greg Kroah-Hartman
maintainerPATCH 269/309 ext4: handle wraparound when searching for blocks for indirect mapped blocks
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Theodore Ts'o <[email protected]>
commit bb81702370fad22c06ca12b6e1648754dbc37e0f upstream.
Commit 4865c768b563 ("ext4: always allocate blocks only from groups inode can use") restricts what blocks will be allocated for indirect block based files to block numbers that fit within 32-bit block numbers.
However, when using a review bot running on the latest Gemini LLM to check this commit when backporting into an LTS based kernel, it raised this concern:
If ac->ac_g_ex.fe_group is >= ngroups (for instance, if the goal group was populated via stream allocation from s_mb_last_groups), then start will be >= ngroups.
Does this allow allocating blocks beyond the 32-bit limit for indirect block mapped files? The commit message mentions that ext4_mb_scan_groups_linear() takes care to not select unsupported groups. However, its loop uses group = *start, and the very first iteration will call ext4_mb_scan_group() with this unsupported group because next_linear_group() is only called at the end of the iteration.
After reviewing the code paths involved and considering the LLM review, I determined that this can happen when there is a file system where some files/directories are extent-mapped and others are indirect-block mapped. To address this, add a safety clamp in ext4_mb_scan_groups().
--- fs/ext4/mballoc.c | 2 ++ 1 file changed, 2 insertions(+)
fs/ext4/mballoc.c +2 -0
@@ -1199,6 +1199,8 @@ static int ext4_mb_scan_groups(struct ex/* searching for the right group start from the goal value specified */ start = ac->ac_g_ex.fe_group; +if (start >= ngroups) + start =0 ; ac->ac_prefetch_grp = start; ac->ac_prefetch_nr =0 ;
Greg Kroah-Hartman
maintainerPATCH 270/309 ext4: fix iloc.bh leak in ext4_fc_replay_inode() error paths
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Baokun Li <[email protected]>
commit ec0a7500d8eace5b4f305fa0c594dd148f0e8d29 upstream.
During code review, Joseph found that ext4_fc_replay_inode() calls ext4_get_fc_inode_loc() to get the inode location, which holds a reference to iloc.bh that must be released via brelse().
However, several error paths jump to the 'out' label without releasing iloc.bh:
- ext4_handle_dirty_metadata() failure
- sync_dirty_buffer() failure
- ext4_mark_inode_used() failure
- ext4_iget() failure
Fix this by introducing an 'out_brelse' label placed just before the existing 'out' label to ensure iloc.bh is always released.
Additionally, make ext4_fc_replay_inode() propagate errors properly instead of always returning 0.
--- fs/ext4/fast_commit.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
fs/ext4/fast_commit.c +8 -5
@@ -1613,19 +1613,21 @@ static int ext4_fc_replay_inode(struct s/* Immediately update the inode on disk. */ ret =ext4_handle_dirty_metadata (NULL ,NULL , iloc.bh);if (ret) - goto out; + goto out_brelse; ret =sync_dirty_buffer (iloc.bh);if (ret) - goto out; + goto out_brelse; ret =ext4_mark_inode_used (sb, ino);if (ret) - goto out; + goto out_brelse;/* Given that we just wrote the inode on disk, this SHOULD succeed. */ inode =ext4_iget (sb, ino,EXT4_IGET_NORMAL );if (IS_ERR (inode)) {ext4_debug ("Inode not found." ); -return -EFSCORRUPTED ; + inode =NULL ; + ret = -EFSCORRUPTED ; + goto out_brelse; }/*
@@ -1642,13 +1644,14 @@ static int ext4_fc_replay_inode(struct sext4_inode_csum_set (inode,ext4_raw_inode (&iloc),EXT4_I (inode)); ret =ext4_handle_dirty_metadata (NULL ,NULL , iloc.bh);sync_dirty_buffer (iloc.bh); +out_brelse:brelse (iloc.bh); out:iput (inode);if (!ret)blkdev_issue_flush (sb->s_bdev); -return 0 ; +return ret; }/*
Greg Kroah-Hartman
maintainerPATCH 271/309 ext4: always drain queued discard work in ext4_mb_release()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Theodore Ts'o <[email protected]>
commit 9ee29d20aab228adfb02ca93f87fb53c56c2f3af upstream.
While reviewing recent ext4 patch[1], Sashiko raised the following concern[2]:
Quoted 5 lines
If the filesystem is initially mounted with the discard option, deleting files will populate
sbi->s_discard_listand queues_discard_work. If it is then remounted with nodiscard, theEXT4_MOUNT_DISCARDflag is cleared, but the pendings_discard_workis neither cancelled nor flushed.
[1] https://lore.kernel.org/r/[email protected]/
[2] https://sashiko.dev/#/patchset/20260319094545.19291-1-qiang.zhang%40linux.dev
The concern was valid, but it had nothing to do with the patch[1]. One of the problems with Sashiko in its current (early) form is that it will detect pre-existing issues and report it as a problem with the patch that it is reviewing.
In practice, it would be hard to hit deliberately (unless you are a malicious syzkaller fuzzer), since it would involve mounting the file system with -o discard, and then deleting a large number of files, remounting the file system with -o nodiscard, and then immediately unmounting the file system before the queued discard work has a change to drain on its own.
Fix it because it's a real bug, and to avoid Sashiko from raising this concern when analyzing future patches to mballoc.c.
--- fs/ext4/mballoc.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-)
fs/ext4/mballoc.c +5 -7
@@ -3890,13 +3890,11 @@ void ext4_mb_release(struct super_blockstruct kmem_cache *cachep =get_groupinfo_cache (sb->s_blocksize_bits);int count; -if (test_opt (sb,DISCARD )) { -/* -* wait the discard work to drain all of ext4_free_data -*/ -flush_work (&sbi->s_discard_work); -WARN_ON_ONCE (!list_empty (&sbi->s_discard_list)); - } +/* +* wait the discard work to drain all of ext4_free_data +*/ +flush_work (&sbi->s_discard_work); +WARN_ON_ONCE (!list_empty (&sbi->s_discard_list)); group_info =rcu_access_pointer (sbi->s_group_info);if (group_info) {
Greg Kroah-Hartman
maintainerPATCH 272/309 arm64: dts: imx8mn-tqma8mqnl: fix LDO5 power off
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Markus Niebel <[email protected]>
commit 8adc841d43ebceabec996c9dcff6e82d3e585268 upstream.
Fix SD card removal caused by automatic LDO5 power off after boot
To prevent this, add vqmmc regulator for USDHC, using a GPIO-controlled regulator that is supplied by LDO5. Since this is implemented on SoM but used on baseboards with SD-card interface, implement the functionality on SoM part and optionally enable it on baseboards if needed.
--- arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl-mba8mx.dts | 13 ++++---- arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi | 22 ++++++++++++++ 2 files changed, 29 insertions(+), 6 deletions(-)
arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl-mba8mx.dts +7 -6
@@ -69,6 +69,10 @@ samsung,esc-clock-frequency = <20000000>; }; +®_usdhc2_vqmmc { + status = "okay"; +}; + &sai3 { assigned-clocks = <&clk IMX8MN_CLK_SAI3>; assigned-clock-parents = <&clk IMX8MN_AUDIO_PLL1_OUT>;
@@ -216,8 +220,7 @@ <MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d4>, <MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d4>, <MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d4>, - <MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d4>, - <MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0x84>; + <MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d4>; }; pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
@@ -226,8 +229,7 @@ <MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d4>, <MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d4>, <MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d4>, - <MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d4>, - <MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0x84>; + <MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d4>; }; pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
@@ -236,8 +238,7 @@ <MX8MN_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d4>, <MX8MN_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d4>, <MX8MN_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d4>, - <MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d4>, - <MX8MN_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0x84>; + <MX8MN_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d4>; }; pinctrl_usdhc2_gpio: usdhc2-gpiogrp {
arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl.dtsi +22 -0
@@ -30,6 +30,20 @@ regulator-max-microvolt = <3300000>; }; + reg_usdhc2_vqmmc: regulator-usdhc2-vqmmc { + compatible = "regulator-gpio"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_usdhc2_vqmmc>; + regulator-name = "V_SD2"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>; + states = <1800000 0x1>, + <3300000 0x0>; + vin-supply = <&ldo5_reg>; + status = "disabled"; + }; + reserved-memory { #address-cells = <2>; #size-cells = <2>;
@@ -233,6 +247,10 @@ vddio-supply = <&ldo3_reg>; }; +&usdhc2 { + vqmmc-supply = <®_usdhc2_vqmmc>; +}; + &usdhc3 { pinctrl-names = "default", "state_100mhz", "state_200mhz"; pinctrl-0 = <&pinctrl_usdhc3>;
@@ -287,6 +305,10 @@ fsl,pins = <MX8MN_IOMUXC_SD2_RESET_B_GPIO2_IO19 0x84>; }; + pinctrl_reg_usdhc2_vqmmc: regusdhc2vqmmcgrp { + fsl,pins = <MX8MN_IOMUXC_GPIO1_IO04_GPIO1_IO4 0xc0>; + }; + pinctrl_usdhc3: usdhc3grp { fsl,pins = <MX8MN_IOMUXC_NAND_WE_B_USDHC3_CLK 0x1d4>, <MX8MN_IOMUXC_NAND_WP_B_USDHC3_CMD 0x1d2>,
Greg Kroah-Hartman
maintainerPATCH 273/309 powerpc64/bpf: do not increment tailcall count when prog is NULL
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hari Bathini <[email protected]>
commit 521bd39d9d28ce54cbfec7f9b89c94ad4fdb8350 upstream.
Do not increment tailcall count, if tailcall did not succeed due to missing BPF program.
[ Conflict due to missing feature commit 2ed2d8f6fb38 ("powerpc64/bpf:
Support tailcalls with subprogs") resolved accordingly. ]
--- arch/powerpc/net/bpf_jit_comp64.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-)
arch/powerpc/net/bpf_jit_comp64.c +14 -9
@@ -430,27 +430,32 @@ static int bpf_jit_emit_tail_call(u32 *i/* * tail_call_cnt++; +* Writeback this updated value only if tailcall succeeds. */ EMIT (PPC_RAW_ADDI (bpf_to_ppc (TMP_REG_1 ),bpf_to_ppc (TMP_REG_1 ),1 )); -EMIT (PPC_RAW_STD (bpf_to_ppc (TMP_REG_1 ), _R1,bpf_jit_stack_tailcallcnt (ctx)));/* prog = array->ptrs[index]; */ -EMIT (PPC_RAW_MULI (bpf_to_ppc (TMP_REG_1 ), b2p_index,8 )); -EMIT (PPC_RAW_ADD (bpf_to_ppc (TMP_REG_1 ),bpf_to_ppc (TMP_REG_1 ), b2p_bpf_array)); -EMIT (PPC_RAW_LD (bpf_to_ppc (TMP_REG_1 ),bpf_to_ppc (TMP_REG_1 ), offsetof(struct bpf_array , ptrs))); +EMIT (PPC_RAW_MULI (bpf_to_ppc (TMP_REG_2 ), b2p_index,8 )); +EMIT (PPC_RAW_ADD (bpf_to_ppc (TMP_REG_2 ),bpf_to_ppc (TMP_REG_2 ), b2p_bpf_array)); +EMIT (PPC_RAW_LD (bpf_to_ppc (TMP_REG_2 ),bpf_to_ppc (TMP_REG_2 ), + offsetof(struct bpf_array , ptrs)));/* * if (prog == NULL) * goto out; */ -EMIT (PPC_RAW_CMPLDI (bpf_to_ppc (TMP_REG_1 ),0 )); +EMIT (PPC_RAW_CMPLDI (bpf_to_ppc (TMP_REG_2 ),0 ));PPC_BCC_SHORT (COND_EQ , out);/* goto *(prog->bpf_func + prologue_size); */ -EMIT (PPC_RAW_LD (bpf_to_ppc (TMP_REG_1 ),bpf_to_ppc (TMP_REG_1 ), offsetof(struct bpf_prog , bpf_func))); -EMIT (PPC_RAW_ADDI (bpf_to_ppc (TMP_REG_1 ),bpf_to_ppc (TMP_REG_1 ), -FUNCTION_DESCR_SIZE + bpf_tailcall_prologue_size)); -EMIT (PPC_RAW_MTCTR (bpf_to_ppc (TMP_REG_1 ))); +EMIT (PPC_RAW_LD (bpf_to_ppc (TMP_REG_2 ),bpf_to_ppc (TMP_REG_2 ), + offsetof(struct bpf_prog , bpf_func))); +EMIT (PPC_RAW_ADDI (bpf_to_ppc (TMP_REG_2 ),bpf_to_ppc (TMP_REG_2 ), +FUNCTION_DESCR_SIZE + bpf_tailcall_prologue_size)); +EMIT (PPC_RAW_MTCTR (bpf_to_ppc (TMP_REG_2 ))); + +/* Writeback updated tailcall count */ +EMIT (PPC_RAW_STD (bpf_to_ppc (TMP_REG_1 ), _R1,bpf_jit_stack_tailcallcnt (ctx)));/* tear down stack, restore NVRs, ... */ bpf_jit_emit_common_epilogue (image, ctx);
Greg Kroah-Hartman
maintainerPATCH 274/309 unwind_user/x86: Fix arch=um build
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peter Zijlstra <[email protected]>
commit aa7387e79a5cff0585cd1b9091944142a06872b6 upstream.
Add CONFIG_HAVE_UNWIND_USER_FP guards to make sure this code doesn't break arch=um builds.
--- arch/x86/include/asm/unwind_user.h | 4 ++++ 1 file changed, 4 insertions(+)
arch/x86/include/asm/unwind_user.h +4 -0
@@ -2,6 +2,8 @@#ifndef _ASM_X86_UNWIND_USER_H#define _ASM_X86_UNWIND_USER_H +#ifdef CONFIG_HAVE_UNWIND_USER_FP +#include <asm/ptrace.h> #include <asm/uprobes.h>
@@ -34,4 +36,6 @@ static inline bool unwind_user_at_functireturn is_uprobe_at_func_entry (regs); } +#endif /* CONFIG_HAVE_UNWIND_USER_FP */ +#endif /* _ASM_X86_UNWIND_USER_H */
Greg Kroah-Hartman
maintainerPATCH 275/309 rust: pin-init: internal: init: document load-bearing fact of field accessors
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Benno Lossin <[email protected]>
commit 580cc37b1de4fcd9997c48d7080e744533f09f36 upstream.
The functions [Pin]Init::__[pinned_]init and ptr::write called from the init! macro require the passed pointer to be aligned. This fact is ensured by the creation of field accessors to previously initialized fields.
Since we missed this very important fact from the beginning [1], document it in the code.
[ Moved changes to the declarative macro, because 6.19.y and earlier do not
have syn. Also duplicated the comment for all field accessor creations.
- Benno ]
--- rust/pin-init/src/macros.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
rust/pin-init/src/macros.rs +16 -0
@@ -1310,6 +1310,10 @@ macro_rules! __init_internal {// return when an error/panic occurs. // We also use the `data` to require the correct trait (`Init` or `PinInit`) for `$field`. unsafe { $data.$field(::core::ptr::addr_of_mut!((*$slot).$field), init)? }; +// NOTE: the field accessor ensures that the initialized field is properly aligned. +// Unaligned fields will cause the compiler to emit E0793. We do not support +// unaligned fields since `Init::__init` requires an aligned pointer; the call to +// `ptr::write` below has the same requirement. // SAFETY: // - the project function does the correct field projection, // - the field has been initialized,
@@ -1349,6 +1353,10 @@ macro_rules! __init_internal {// return when an error/panic occurs. unsafe { $crate::Init ::__init (init, ::core::ptr::addr_of_mut!((*$slot).$field))? }; +// NOTE: the field accessor ensures that the initialized field is properly aligned. +// Unaligned fields will cause the compiler to emit E0793. We do not support +// unaligned fields since `Init::__init` requires an aligned pointer; the call to +// `ptr::write` below has the same requirement. // SAFETY: // - the field is not structurally pinned, since the line above must compile, // - the field has been initialized,
@@ -1389,6 +1397,10 @@ macro_rules! __init_internal {unsafe { ::core::ptr::write (::core::ptr::addr_of_mut!((*$slot).$field), $field) }; } +// NOTE: the field accessor ensures that the initialized field is properly aligned. +// Unaligned fields will cause the compiler to emit E0793. We do not support +// unaligned fields since `Init::__init` requires an aligned pointer; the call to +// `ptr::write` below has the same requirement. #[allow(unused_variables)] // SAFETY: // - the field is not structurally pinned, since no `use_data` was required to create this
@@ -1429,6 +1441,10 @@ macro_rules! __init_internal {// SAFETY: The memory at `slot` is uninitialized. unsafe { ::core::ptr::write (::core::ptr::addr_of_mut!((*$slot).$field), $field) }; } +// NOTE: the field accessor ensures that the initialized field is properly aligned. +// Unaligned fields will cause the compiler to emit E0793. We do not support +// unaligned fields since `Init::__init` requires an aligned pointer; the call to +// `ptr::write` below has the same requirement. // SAFETY: // - the project function does the correct field projection, // - the field has been initialized,
Greg Kroah-Hartman
maintainerPATCH 276/309 drm/amd/pm: fix amdgpu_irq enabled counter unbalanced on smu v11.0
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Wang <[email protected]>
commit e12603bf2c3d571476a21debfeab80bb70d8c0cc upstream.
v1:
- fix amdgpu_irq enabled counter unbalanced issue on smu_v11_0_disable_thermal_alert.
v2:
- re-enable smu thermal alert to make amdgpu irq counter balance for smu v11.0 if in runpm state
[75582.361561] ------------[ cut here ]------------ [75582.361565] WARNING: CPU: 42 PID: 533 at drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c:639 amdgpu_irq_put+0xd8/0xf0 [amdgpu] ... [75582.362211] Tainted: [E]=UNSIGNED_MODULE [75582.362214] Hardware name: GIGABYTE MZ01-CE0-00/MZ01-CE0-00, BIOS F14a 08/14/2020 [75582.362218] Workqueue: pm pm_runtime_work [75582.362225] RIP: 0010:amdgpu_irq_put+0xd8/0xf0 [amdgpu] [75582.362556] Code: 31 f6 31 ff e9 c9 bf cf c2 44 89 f2 4c 89 e6 4c 89 ef e8 db fc ff ff 5b 41 5c 41 5d 41 5e 5d 31 d2 31 f6 31 ff e9 a8 bf cf c2 <0f> 0b eb c3 b8 fe ff ff ff eb 97 e9 84 e8 8b 00 0f 1f 84 00 00 00 [75582.362560] RSP: 0018:ffffd50d51297b80 EFLAGS: 00010246 [75582.362564] RAX: 0000000000000000 RBX: 0000000000000001 RCX: 0000000000000000 [75582.362568] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 [75582.362570] RBP: ffffd50d51297ba0 R08: 0000000000000000 R09: 0000000000000000 [75582.362573] R10: 0000000000000000 R11: 0000000000000000 R12: ffff8e72091d2008 [75582.362576] R13: ffff8e720af80000 R14: 0000000000000000 R15: ffff8e720af80000 [75582.362579] FS: 0000000000000000(0000) GS:ffff8e9158262000(0000) knlGS:0000000000000000 [75582.362582] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [75582.362585] CR2: 000074869d040c14 CR3: 0000001e37a3e000 CR4: 00000000003506f0 [75582.362588] Call Trace: [75582.362591] <TASK> [75582.362597] smu_v11_0_disable_thermal_alert+0x17/0x30 [amdgpu] [75582.362983] smu_smc_hw_cleanup+0x79/0x4f0 [amdgpu] [75582.363375] smu_suspend+0x92/0x110 [amdgpu] [75582.363762] ? gfx_v10_0_hw_fini+0xd5/0x150 [amdgpu] [75582.364098] amdgpu_ip_block_suspend+0x27/0x80 [amdgpu] [75582.364377] ? timer_delete_sync+0x10/0x20 [75582.364384] amdgpu_device_ip_suspend_phase2+0x190/0x450 [amdgpu] [75582.364665] amdgpu_device_suspend+0x1ae/0x2f0 [amdgpu] [75582.364948] amdgpu_pmops_runtime_suspend+0xf3/0x1f0 [amdgpu] [75582.365230] pci_pm_runtime_suspend+0x6d/0x1f0 [75582.365237] ? __pfx_pci_pm_runtime_suspend+0x10/0x10 [75582.365242] __rpm_callback+0x4c/0x190 [75582.365246] ? srso_return_thunk+0x5/0x5f [75582.365252] ? srso_return_thunk+0x5/0x5f [75582.365256] ? ktime_get_mono_fast_ns+0x43/0xe0 [75582.365263] rpm_callback+0x6e/0x80 [75582.365267] rpm_suspend+0x124/0x5f0 [75582.365271] ? srso_return_thunk+0x5/0x5f [75582.365275] ? __schedule+0x439/0x15e0 [75582.365281] ? srso_return_thunk+0x5/0x5f [75582.365285] ? __queue_delayed_work+0xb8/0x180 [75582.365293] pm_runtime_work+0xc6/0xe0 [75582.365297] process_one_work+0x1a1/0x3f0 [75582.365303] worker_thread+0x2ba/0x3d0 [75582.365309] kthread+0x107/0x220 [75582.365313] ? __pfx_worker_thread+0x10/0x10 [75582.365318] ? __pfx_kthread+0x10/0x10 [75582.365323] ret_from_fork+0xa2/0x120 [75582.365328] ? __pfx_kthread+0x10/0x10 [75582.365332] ret_from_fork_asm+0x1a/0x30 [75582.365343] </TASK> [75582.365345] ---[ end trace 0000000000000000 ]--- [75582.365350] amdgpu 0000:05:00.0: amdgpu: Fail to disable thermal alert! [75582.365379] amdgpu 0000:05:00.0: amdgpu: suspend of IP block <smu> failed -22
--- drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 7 +++++-- drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c | 7 ++++++- 2 files changed, 11 insertions(+), 3 deletions(-)
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +5 -2
@@ -1655,9 +1655,12 @@ static int smu_smc_hw_setup(struct smu_cif (adev->in_suspend &&smu_is_dpm_running (smu)) {dev_info (adev->dev,"dpm has been enabled\n" ); ret =smu_system_features_control (smu, true); -if (ret) +if (ret) {dev_err (adev->dev,"Failed system features control!\n" ); -return ret; +return ret; + } + +return smu_enable_thermal_alert (smu); }break ;default :
drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c +6 -1
@@ -1022,7 +1022,12 @@ int smu_v11_0_enable_thermal_alert(strucint smu_v11_0_disable_thermal_alert (struct smu_context *smu) { -return amdgpu_irq_put (smu->adev, &smu->irq_source,0 ); +int ret =0 ; + +if (smu->smu_table.thermal_controller_type) + ret =amdgpu_irq_put (smu->adev, &smu->irq_source,0 ); + +return ret; }static uint16_t convert_to_vddc (uint8_t vid)
Greg Kroah-Hartman
maintainerPATCH 277/309 mm/damon/stat: monitor all System RAM resources
In reply to Greg Kroah-Hartman6.18-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 | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-)
mm/damon/stat.c +34 -2
@@ -145,12 +145,44 @@ 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 int damon_stat_set_monitoring_region (struct damon_target *t, +unsigned long addr_unit) +{ +struct damon_addr_range addr_range; +struct damon_stat_system_ram_range_walk_arg arg = {}; + +walk_system_ram_res (0 ,ULONG_MAX , &arg, damon_stat_system_ram_walk_fn); +if (!arg.walked) +return -EINVAL ; + addr_range.start = arg.res.start; + addr_range.end = arg.res.end +1 ; +if (addr_range.end <= addr_range.start) +return -EINVAL ; +return damon_set_regions (t, &addr_range,1 ,DAMON_MIN_REGION ); +} +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,7 +220,7 @@ 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)) +if (damon_stat_set_monitoring_region (target, ctx->addr_unit)) goto free_out;return ctx; free_out:
Greg Kroah-Hartman
maintainerPATCH 278/309 mm/damon/core: avoid use of half-online-committed context
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: SeongJae Park <[email protected]>
commit 26f775a054c3cda86ad465a64141894a90a9e145 upstream.
One major usage of damon_call() is online DAMON parameters update. It is done by calling damon_commit_ctx() inside the damon_call() callback function. damon_commit_ctx() can fail for two reasons: 1) invalid parameters and 2) internal memory allocation failures. In case of failures, the damon_ctx that attempted to be updated (commit destination) can be partially updated (or, corrupted from a perspective), and therefore shouldn't be used anymore. The function only ensures the damon_ctx object can safely deallocated using damon_destroy_ctx().
The API callers are, however, calling damon_commit_ctx() only after asserting the parameters are valid, to avoid damon_commit_ctx() fails due to invalid input parameters. But it can still theoretically fail if the internal memory allocation fails. In the case, DAMON may run with the partially updated damon_ctx. This can result in unexpected behaviors including even NULL pointer dereference in case of damos_commit_dests() failure [1]. Such allocation failure is arguably too small to fail, so the real world impact would be rare. But, given the bad consequence, this needs to be fixed.
Avoid such partially-committed (maybe-corrupted) damon_ctx use by saving the damon_commit_ctx() failure on the damon_ctx object. For this, introduce damon_ctx->maybe_corrupted field. damon_commit_ctx() sets it when it is failed. kdamond_call() checks if the field is set after each damon_call_control->fn() is executed. If it is set, ignore remaining callback requests and return. All kdamond_call() callers including kdamond_fn() also check the maybe_corrupted field right after kdamond_call() invocations. If the field is set, break the kdamond_fn() main loop so that DAMON sill doesn't use the context that might be corrupted.
--- include/linux/damon.h | 6 ++++++ mm/damon/core.c | 8 ++++++++ 2 files changed, 14 insertions(+)
include/linux/damon.h +6 -0
@@ -786,6 +786,12 @@ struct damon_ctx {struct damos_walk_control *walk_control;struct mutex walk_control_lock; +/* +* indicate if this may be corrupted. Currentonly this is set only for +* damon_commit_ctx() failure. +*/ +bool maybe_corrupted; +/* public: */ struct task_struct *kdamond;struct mutex kdamond_lock;
mm/damon/core.c +8 -0
@@ -1236,6 +1236,7 @@ int damon_commit_ctx(struct damon_ctx *d {int err; + dst->maybe_corrupted = true;if (!is_power_of_2 (src->min_sz_region))return -EINVAL ;
@@ -1261,6 +1262,7 @@ int damon_commit_ctx(struct damon_ctx *d dst->addr_unit = src->addr_unit; dst->min_sz_region = src->min_sz_region; + dst->maybe_corrupted = false;return 0 ; }
@@ -2562,6 +2564,8 @@ static void kdamond_call(struct damon_ct }else {list_add (&control->list, &repeat_controls); } +if (!cancel && ctx->maybe_corrupted) +break ; } control =list_first_entry_or_null (&repeat_controls, struct damon_call_control, list);
@@ -2594,6 +2598,8 @@ static int kdamond_wait_activation(struckdamond_usleep (min_wait_time);kdamond_call (ctx, false); +if (ctx->maybe_corrupted) +return -EINVAL ;damos_walk_cancel (ctx); }return -EBUSY ;
@@ -2679,6 +2685,8 @@ static int kdamond_fn(void *data)* kdamond_merge_regions() if possible, to reduce overhead */ kdamond_call (ctx, false); +if (ctx->maybe_corrupted) +break ;if (!list_empty (&ctx->schemes))kdamond_apply_schemes (ctx);else
Greg Kroah-Hartman
maintainerPATCH 279/309 mm/damon/sysfs: fix param_ctx leak on damon_sysfs_new_test_ctx() failure
In reply to Greg Kroah-Hartman6.18-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
@@ -1476,8 +1476,10 @@ static int damon_sysfs_commit_input(voidif (IS_ERR (param_ctx))return PTR_ERR (param_ctx); test_ctx =damon_new_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/309 mm/huge_memory: fix folio isnt locked in softleaf_to_folio()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jinjiang Tu <[email protected]>
[ Upstream commit 4c5e7f0fcd592801c9cc18f29f80fbee84eb8669 ]
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/swapops.h | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-)
include/linux/swapops.h +19 -8
@@ -487,15 +487,29 @@ static inline int pte_none_mostly(pte_treturn pte_none (pte) ||is_pte_marker (pte); } -static inline struct page *pfn_swap_entry_to_page (swp_entry_t entry) +static inline void swap_entry_migration_sync (swp_entry_t entry, +struct folio *folio) { -struct page *p =pfn_to_page (swp_offset_pfn (entry)); +/* +* 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 */ -BUG_ON (is_migration_entry (entry) && !PageLocked (p)); +BUG_ON (!folio_test_locked (folio)); +} + +static inline struct page *pfn_swap_entry_to_page (swp_entry_t entry) +{ +struct page *p =pfn_to_page (swp_offset_pfn (entry)); + +if (is_migration_entry (entry)) +swap_entry_migration_sync (entry,page_folio (p));return p; }
@@ -504,11 +518,8 @@ static inline struct folio *pfn_swap_ent {struct folio *folio =pfn_folio (swp_offset_pfn (entry)); -/* -* Any use of migration entries may only occur while the -* corresponding folio is locked -*/ -BUG_ON (is_migration_entry (entry) && !folio_test_locked (folio)); +if (is_migration_entry (entry)) +swap_entry_migration_sync (entry, folio);return folio; }
Greg Kroah-Hartman
maintainerPATCH 281/309 ksmbd: fix use-after-free and NULL deref in smb_grant_oplock()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Werner Kasselman <[email protected]>
[ Upstream commit 48623ec358c1c600fa1e38368746f933e0f1a617 ]
smb_grant_oplock() has two issues in the oplock publication sequence:
1) opinfo is linked into ci->m_op_list (via opinfo_add) before add_lease_global_list() is called. If add_lease_global_list() fails (kmalloc returns NULL), the error path frees the opinfo via __free_opinfo() while it is still linked in ci->m_op_list. Concurrent m_op_list readers (opinfo_get_list, or direct iteration in smb_break_all_levII_oplock) dereference the freed node.
2) opinfo->o_fp is assigned after add_lease_global_list() publishes the opinfo on the global lease list. A concurrent find_same_lease_key() can walk the lease list and dereference opinfo->o_fp->f_ci while o_fp is still NULL.
Fix by restructuring the publication sequence to eliminate post-publish failure:
- Set opinfo->o_fp before any list publication (fixes NULL deref).
- Preallocate lease_table via alloc_lease_table() before opinfo_add() so add_lease_global_list() becomes infallible after publication.
- Keep the original m_op_list publication order (opinfo_add before lease list) so concurrent opens via same_client_has_lease() and opinfo_get_list() still see the in-flight grant.
- Use opinfo_put() instead of __free_opinfo() on err_out so that the RCU-deferred free path is used.
This also requires splitting add_lease_global_list() to take a preallocated lease_table and changing its return type from int to void, since it can no longer fail.
--- fs/smb/server/oplock.c | 72 ++++++++++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 27 deletions(-)
fs/smb/server/oplock.c +45 -27
@@ -82,11 +82,19 @@ static void lease_del_list(struct oplockspin_unlock (&lb->lb_lock); } -static void lb_add (struct lease_table *lb) +static struct lease_table *alloc_lease_table (struct oplock_info *opinfo) { -write_lock (&lease_list_lock); -list_add (&lb->l_entry, &lease_table_list); -write_unlock (&lease_list_lock); +struct lease_table *lb; + + lb =kmalloc (sizeof (struct lease_table ),KSMBD_DEFAULT_GFP ); +if (!lb) +return NULL ; + +memcpy (lb->client_guid, opinfo->conn->ClientGUID, +SMB2_CLIENT_GUID_SIZE ); +INIT_LIST_HEAD (&lb->lease_list); +spin_lock_init (&lb->lb_lock); +return lb; }static int alloc_lease (struct oplock_info *opinfo,struct lease_ctx_info *lctx)
@@ -1042,34 +1050,27 @@ static void copy_lease(struct oplock_inf lease2->version = lease1->version; } -static int add_lease_global_list (struct oplock_info *opinfo) +static void add_lease_global_list (struct oplock_info *opinfo, +struct lease_table *new_lb) {struct lease_table *lb; -read_lock (&lease_list_lock); +write_lock (&lease_list_lock);list_for_each_entry (lb, &lease_table_list, l_entry) {if (!memcmp (lb->client_guid, opinfo->conn->ClientGUID,SMB2_CLIENT_GUID_SIZE )) { opinfo->o_lease->l_lb = lb;lease_add_list (opinfo); -read_unlock (&lease_list_lock); -return 0 ; +write_unlock (&lease_list_lock); +kfree (new_lb); +return ; } } -read_unlock (&lease_list_lock); - lb =kmalloc (sizeof (struct lease_table ),KSMBD_DEFAULT_GFP ); -if (!lb) -return -ENOMEM ; - -memcpy (lb->client_guid, opinfo->conn->ClientGUID, -SMB2_CLIENT_GUID_SIZE ); -INIT_LIST_HEAD (&lb->lease_list); -spin_lock_init (&lb->lb_lock); - opinfo->o_lease->l_lb = lb; + opinfo->o_lease->l_lb = new_lb;lease_add_list (opinfo); -lb_add (lb); -return 0 ; +list_add (&new_lb->l_entry, &lease_table_list); +write_unlock (&lease_list_lock); } static void set_oplock_level(struct oplock_info *opinfo, int level,
@@ -1189,6 +1190,7 @@ int smb_grant_oplock(struct ksmbd_work *int err =0 ;struct oplock_info *opinfo =NULL , *prev_opinfo =NULL ;struct ksmbd_inode *ci = fp->f_ci; +struct lease_table *new_lb =NULL ;bool prev_op_has_lease;__le32 prev_op_state =0 ;
@@ -1291,21 +1293,37 @@ set_lev:set_oplock_level (opinfo, req_op_level, lctx); out: -opinfo_count_inc (fp); -opinfo_add (opinfo, fp); - +/* +* Set o_fp before any publication so that concurrent readers +* (e.g. find_same_lease_key() on the lease list) that +* dereference opinfo->o_fp don't hit a NULL pointer. +* +* Keep the original publication order so concurrent opens can +* still observe the in-flight grant via ci->m_op_list, but make +* everything after opinfo_add() no-fail by preallocating any new +* lease_table first. +*/ + opinfo->o_fp = fp;if (opinfo->is_lease) { - err =add_lease_global_list (opinfo); -if (err) + new_lb =alloc_lease_table (opinfo); +if (!new_lb) { + err = -ENOMEM ; goto err_out; + } } +opinfo_count_inc (fp); +opinfo_add (opinfo, fp); + +if (opinfo->is_lease) +add_lease_global_list (opinfo, new_lb); +rcu_assign_pointer (fp->f_opinfo, opinfo); - opinfo->o_fp = fp;return 0 ; err_out: -__free_opinfo (opinfo); +kfree (new_lb); +opinfo_put (opinfo);return err; }
Greg Kroah-Hartman
maintainerPATCH 282/309 mm/mseal: update VMA end correctly on merge
In reply to Greg Kroah-Hartman6.18-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 | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
mm/mseal.c +2 -3
@@ -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,7 +65,8 @@ static int mseal_apply(struct mm_struct prev = vma;for_each_vma_range (vmi, vma, end) { -unsigned long curr_end =MIN (vma->vm_end, 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 )) { vma = vma_modify_flags(&vmi, prev, vma,
@@ -78,7 +78,6 @@ static int mseal_apply(struct mm_struct } prev = vma; - curr_start = curr_end; }return 0 ;
Greg Kroah-Hartman
maintainerPATCH 283/309 dmaengine: idxd: Fix crash when the event log is disabled
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vinicius Costa Gomes <[email protected]>
[ Upstream commit 52d2edea0d63c935e82631e4b9e4a94eccf97b5b ]
If reporting errors to the event log is not supported by the hardware, and an error that causes Function Level Reset (FLR) is received, the driver will try to restore the event log even if it was not allocated.
Also, only try to free the event log if it was properly allocated.
--- drivers/dma/idxd/device.c | 3 +++ drivers/dma/idxd/init.c | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-)
drivers/dma/idxd/device.c +3 -0
@@ -815,6 +815,9 @@ static void idxd_device_evl_free(struct idxd_device *idxd)struct device *dev = &idxd->pdev->dev;struct idxd_evl *evl = idxd->evl; +if (!evl) +return ; + gencfg.bits =ioread32 (idxd->reg_base +IDXD_GENCFG_OFFSET );if (!gencfg.evl_en)return ;
drivers/dma/idxd/init.c +2 -1
@@ -962,7 +962,8 @@ static void idxd_device_config_restore(struct idxd_device *idxd, idxd->rdbuf_limit = idxd_saved->saved_idxd.rdbuf_limit; - idxd->evl->size = saved_evl->size; +if (idxd->evl) + idxd->evl->size = saved_evl->size;for (i =0 ; i < idxd->max_groups; i++) {struct idxd_group *saved_group, *group;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 284/309 dmaengine: idxd: Fix possible invalid memory access after FLR
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vinicius Costa Gomes <[email protected]>
[ Upstream commit d6077df7b75d26e4edf98983836c05d00ebabd8d ]
In the case that the first Function Level Reset (FLR) concludes correctly, but in the second FLR the scratch area for the saved configuration cannot be allocated, it's possible for a invalid memory access to happen.
Always set the deallocated scratch area to NULL after FLR completes.
--- drivers/dma/idxd/init.c | 1 + 1 file changed, 1 insertion(+)
drivers/dma/idxd/init.c +1 -0
@@ -1137,6 +1137,7 @@ static void idxd_reset_done(struct pci_dev *pdev) } out:kfree (idxd->idxd_saved); + idxd->idxd_saved =NULL ; }static const struct pci_error_handlers idxd_error_handler = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 285/309 dmaengine: idxd: Fix not releasing workqueue on .release()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vinicius Costa Gomes <[email protected]>
[ Upstream commit 3d33de353b1ff9023d5ec73b9becf80ea87af695 ]
The workqueue associated with an DSA/IAA device is not released when the object is freed.
--- drivers/dma/idxd/sysfs.c | 1 + 1 file changed, 1 insertion(+)
drivers/dma/idxd/sysfs.c +1 -0
@@ -1812,6 +1812,7 @@ static void idxd_conf_device_release(struct device *dev) {struct idxd_device *idxd =confdev_to_idxd (dev); +destroy_workqueue (idxd->wq);kfree (idxd->groups);bitmap_free (idxd->wq_enable_map);kfree (idxd->wqs);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 286/309 dmaengine: idxd: Fix memory leak when a wq is reset
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vinicius Costa Gomes <[email protected]>
[ Upstream commit d9cfb5193a047a92a4d3c0e91ea4cc87c8f7c478 ]
idxd_wq_disable_cleanup() which is called from the reset path for a workqueue, sets the wq type to NONE, which for other parts of the driver mean that the wq is empty (all its resources were released).
Only set the wq type to NONE after its resources are released.
--- drivers/dma/idxd/device.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/dma/idxd/device.c +1 -2
@@ -174,6 +174,7 @@ void idxd_wq_free_resources(struct idxd_wq *wq)free_descs (wq);dma_free_coherent (dev, wq->compls_size, wq->compls, wq->compls_addr);sbitmap_queue_free (&wq->sbq); + wq->type =IDXD_WQT_NONE ; }EXPORT_SYMBOL_NS_GPL (idxd_wq_free_resources,"IDXD" );
@@ -367,7 +368,6 @@ static void idxd_wq_disable_cleanup(struct idxd_wq *wq)lockdep_assert_held (&wq->wq_lock); wq->state =IDXD_WQ_DISABLED ;memset (wq->wqcfg,0 , idxd->wqcfg_size); - wq->type =IDXD_WQT_NONE ; wq->threshold =0 ; wq->priority =0 ; wq->enqcmds_retries =IDXD_ENQCMDS_RETRIES ;
@@ -1516,7 +1516,6 @@ void idxd_drv_disable_wq(struct idxd_wq *wq)idxd_wq_reset (wq);idxd_wq_free_resources (wq);percpu_ref_exit (&wq->wq_active); - wq->type =IDXD_WQT_NONE ; wq->client_count =0 ; }EXPORT_SYMBOL_NS_GPL (idxd_drv_disable_wq,"IDXD" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 287/309 dmaengine: idxd: Fix freeing the allocated ida too late
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vinicius Costa Gomes <[email protected]>
[ Upstream commit c311f5e9248471a950f0a524c2fd736414d98900 ]
It can happen that when the cdev .release() is called, the driver already called ida_destroy(). Move ida_free() to the _del() path.
We see with DEBUG_KOBJECT_RELEASE enabled and forcing an early PCI unbind.
--- drivers/dma/idxd/cdev.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/dma/idxd/cdev.c +4 -4
@@ -158,11 +158,7 @@ static const struct device_type idxd_cdev_file_type = {static void idxd_cdev_dev_release (struct device *dev) {struct idxd_cdev *idxd_cdev =dev_to_cdev (dev); -struct idxd_cdev_context *cdev_ctx; -struct idxd_wq *wq = idxd_cdev->wq; - cdev_ctx = &ictx[wq->idxd->data->type]; -ida_free (&cdev_ctx->minor_ida, idxd_cdev->minor);kfree (idxd_cdev); }
@@ -582,11 +578,15 @@ int idxd_wq_add_cdev(struct idxd_wq *wq)void idxd_wq_del_cdev (struct idxd_wq *wq) { +struct idxd_cdev_context *cdev_ctx;struct idxd_cdev *idxd_cdev; idxd_cdev = wq->idxd_cdev; wq->idxd_cdev =NULL ;cdev_device_del (&idxd_cdev->cdev,cdev_dev (idxd_cdev)); + + cdev_ctx = &ictx[wq->idxd->data->type]; +ida_free (&cdev_ctx->minor_ida, idxd_cdev->minor);put_device (cdev_dev (idxd_cdev)); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 288/309 dmaengine: idxd: Fix leaking event log memory
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vinicius Costa Gomes <[email protected]>
[ Upstream commit ee66bc29578391c9b48523dc9119af67bd5c7c0f ]
During the device remove process, the device is reset, causing the configuration registers to go back to their default state, which is zero. As the driver is checking if the event log support was enabled before deallocating, it will fail if a reset happened before.
Do not check if the support was enabled, the check for 'idxd->evl' being valid (only allocated if the HW capability is available) is enough.
--- drivers/dma/idxd/device.c | 4 ---- 1 file changed, 4 deletions(-)
drivers/dma/idxd/device.c +0 -4
@@ -818,10 +818,6 @@ static void idxd_device_evl_free(struct idxd_device *idxd)if (!evl)return ; - gencfg.bits =ioread32 (idxd->reg_base +IDXD_GENCFG_OFFSET ); -if (!gencfg.evl_en) -return ; -mutex_lock (&evl->lock); gencfg.evl_en =0 ;iowrite32 (gencfg.bits, idxd->reg_base +IDXD_GENCFG_OFFSET );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 289/309 phy: ti: j721e-wiz: Fix device node reference leak in wiz_get_lane_phy_types()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Gu <[email protected]>
[ Upstream commit 584b457f4166293bdfa50f930228e9fb91a38392 ]
The serdes device_node is obtained using of_get_child_by_name(), which increments the reference count. However, it is never put, leading to a reference leak.
Add the missing of_node_put() calls to ensure the reference count is properly balanced.
--- drivers/phy/ti/phy-j721e-wiz.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/phy/ti/phy-j721e-wiz.c +2 -0
@@ -1425,6 +1425,7 @@ static int wiz_get_lane_phy_types(struct device *dev, struct wiz *wiz)dev_err (dev,"%s: Reading \"reg\" from \"%s\" failed: %d\n" , __func__, subnode->name, ret); +of_node_put (serdes);return ret; }of_property_read_u32 (subnode,"cdns,num-lanes" , &num_lanes);
@@ -1439,6 +1440,7 @@ static int wiz_get_lane_phy_types(struct device *dev, struct wiz *wiz) } } +of_node_put (serdes);return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 290/309 dmaengine: dw-edma: Fix multiple times setting of the CYCLE_STATE and CYCLE_BIT bits for HDMA.
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: LUO Haowen <[email protected]>
[ Upstream commit 3f63297ff61a994b99d710dcb6dbde41c4003233 ]
Others have submitted this issue (https://lore.kernel.org/dmaengine/
[email protected]/),
but it has not been fixed yet. Therefore, more supplementary information is provided here.
As mentioned in the "PCS-CCS-CB-TCB" Producer-Consumer Synchronization of "DesignWare Cores PCI Express Controller Databook, version 6.00a":
1. The Consumer CYCLE_STATE (CCS) bit in the register only needs to be initialized once; the value will update automatically to be ~CYCLE_BIT (CB) in the next chunk.
2. The Consumer CYCLE_BIT bit in the register is loaded from the LL element and tested against CCS. When CB = CCS, the data transfer is executed. Otherwise not.
The current logic sets customer (HDMA) CS and CB bits to 1 in each chunk while setting the producer (software) CB of odd chunks to 0 and even chunks to 1 in the linked list. This is leading to a mismatch between the producer CB and consumer CS bits.
This issue can be reproduced by setting the transmission data size to exceed one chunk. By the way, in the EDMA using the same "PCS-CCS-CB-TCB" mechanism, the CS bit is only initialized once and this issue was not found. Refer to drivers/dma/dw-edma/dw-edma-v0-core.c:dw_edma_v0_core_start.
So fix this issue by initializing the CYCLE_STATE and CYCLE_BIT bits only once.
--- drivers/dma/dw-edma/dw-hdma-v0-core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/dma/dw-edma/dw-hdma-v0-core.c +3 -3
@@ -252,10 +252,10 @@ static void dw_hdma_v0_core_start(struct dw_edma_chunk *chunk, bool first) lower_32_bits(chunk->ll_region.paddr));SET_CH_32 (dw, chan->dir, chan->id, llp.msb,upper_32_bits (chunk->ll_region.paddr)); +/* Set consumer cycle */ +SET_CH_32 (dw, chan->dir, chan->id, cycle_sync, +HDMA_V0_CONSUMER_CYCLE_STAT |HDMA_V0_CONSUMER_CYCLE_BIT ); } -/* Set consumer cycle */ -SET_CH_32 (dw, chan->dir, chan->id, cycle_sync, -HDMA_V0_CONSUMER_CYCLE_STAT |HDMA_V0_CONSUMER_CYCLE_BIT );dw_hdma_v0_sync_ll_data (chunk);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 291/309 dmaengine: xilinx: xdma: Fix regmap init error handling
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexander Stein <[email protected]>
[ Upstream commit e0adbf74e2a0455a6bc9628726ba87bcd0b42bf8 ]
devm_regmap_init_mmio returns an ERR_PTR() upon error, not NULL. Fix the error check and also fix the error message. Use the error code from ERR_PTR() instead of the wrong value in ret.
--- drivers/dma/xilinx/xdma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/dma/xilinx/xdma.c +2 -2
@@ -1236,8 +1236,8 @@ static int xdma_probe(struct platform_device *pdev) xdev->rmap =devm_regmap_init_mmio (&pdev->dev, reg_base, &xdma_regmap_config); -if (!xdev->rmap) { -xdma_err (xdev,"config regmap failed: %d" , ret); +if (IS_ERR (xdev->rmap)) { +xdma_err (xdev,"config regmap failed: %pe" , xdev->rmap); goto failed; }INIT_LIST_HEAD (&xdev->dma_dev.channels);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 292/309 netfs: Fix kernel BUG in netfs_limit_iter() for ITER_KVEC iterators
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Deepanshu Kartikey <[email protected]>
[ Upstream commit 67e467a11f62ff64ad219dc6aa5459e132c79d14 ]
When a process crashes and the kernel writes a core dump to a 9P filesystem, __kernel_write() creates an ITER_KVEC iterator. This iterator reaches netfs_limit_iter() via netfs_unbuffered_write(), which only handles ITER_FOLIOQ, ITER_BVEC and ITER_XARRAY iterator types, hitting the BUG() for any other type.
Fix this by adding netfs_limit_kvec() following the same pattern as netfs_limit_bvec(), since both kvec and bvec are simple segment arrays with pointer and length fields. Dispatch it from netfs_limit_iter() when the iterator type is ITER_KVEC.
--- fs/netfs/iterator.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+)
fs/netfs/iterator.c +43 -0
@@ -142,6 +142,47 @@ static size_t netfs_limit_bvec(const struct iov_iter *iter, size_t start_offset,return min (span, max_size); } +/* +* Select the span of a kvec iterator we're going to use. Limit it by both +* maximum size and maximum number of segments. Returns the size of the span +* in bytes. +*/ +static size_t netfs_limit_kvec (const struct iov_iter *iter,size_t start_offset, +size_t max_size,size_t max_segs) +{ +const struct kvec *kvecs = iter->kvec; +unsigned int nkv = iter->nr_segs, ix =0 , nsegs =0 ; +size_t len, span =0 , n = iter->count; +size_t skip = iter->iov_offset + start_offset; + +if (WARN_ON (!iov_iter_is_kvec (iter)) || +WARN_ON (start_offset > n) || + n ==0 ) +return 0 ; + +while (n && ix < nkv && skip) { + len = kvecs[ix].iov_len; +if (skip < len) +break ; + skip -= len; + n -= len; + ix++; + } + +while (n && ix < nkv) { + len =min3 (n, kvecs[ix].iov_len - skip, max_size); + span += len; + nsegs++; + ix++; +if (span >= max_size || nsegs >= max_segs) +break ; + skip =0 ; + n -= len; + } + +return min (span, max_size); +} +/* * Select the span of an xarray iterator we're going to use. Limit it by both * maximum size and maximum number of segments. It is assumed that segments
@@ -245,6 +286,8 @@ size_t netfs_limit_iter(const struct iov_iter *iter, size_t start_offset,return netfs_limit_bvec (iter, start_offset, max_size, max_segs);if (iov_iter_is_xarray (iter))return netfs_limit_xarray (iter, start_offset, max_size, max_segs); +if (iov_iter_is_kvec (iter)) +return netfs_limit_kvec (iter, start_offset, max_size, max_segs);BUG (); }EXPORT_SYMBOL (netfs_limit_iter);
Signature · 1 line
2.53.0