6.12.110-rc1 review
Subsystems (7)
Greg Kroah-Hartman
maintainerPATCH 271/1376 drm/gud: NUL-terminate TV mode names read from the device
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Deepanshu Kartikey <[email protected]>
commit 500cb24cd61bad8a2747ddfc49b7034899c82d94 upstream.
gud_connector_add_tv_mode() reads a buffer of fixed-size mode names from the USB device and passes pointers into it to drm_mode_create_tv_properties_legacy(), which calls strlen() on each one. Nothing guarantees the device NUL-terminates a name, so strlen() can run past the end of a slot and, for the last mode, past the end of the allocation.
Terminate each name at the end of its slot before use.
--- drivers/gpu/drm/gud/gud_connector.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/gpu/drm/gud/gud_connector.c +7 -2
@@ -397,8 +397,13 @@ static int gud_connector_add_tv_mode(str } num_modes = ret /GUD_CONNECTOR_TV_MODE_NAME_LEN ; -for (i =0 ; i < num_modes; i++) - modes[i] = &buf[i *GUD_CONNECTOR_TV_MODE_NAME_LEN ]; +for (i =0 ; i < num_modes; i++) { +char *mode = &buf[i *GUD_CONNECTOR_TV_MODE_NAME_LEN ]; + +/* The device is not trusted to NUL-terminate the name */ + mode[GUD_CONNECTOR_TV_MODE_NAME_LEN -1 ] ='\0' ; + modes[i] = mode; + } ret =drm_mode_create_tv_properties_legacy (connector->dev, num_modes, modes); free:
Greg Kroah-Hartman
maintainerPATCH 272/1376 drm/gud: validate TV mode names before creating enum property
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tao Yu <[email protected]>
commit da1ea35fea67ad841f4ada28dd61b41be65e5437 upstream.
The GUD protocol returns TV mode names as fixed-size GUD_CONNECTOR_TV_MODE_NAME_LEN entries and requires each name to be NUL-terminated.
gud_connector_add_tv_mode() currently passes each fixed-size entry directly to drm_mode_create_tv_properties_legacy(), which eventually reaches drm_property_add_enum() and strlen(). If a device returns an entry without a terminating NUL byte, strlen() reads past the end of the slot and can run beyond the allocated buffer, triggering an out-of-bounds read.
Validate that each returned TV mode name contains a NUL terminator within its fixed-size slot before passing it to the DRM property code. If a malformed entry is found, reject the device response with -EIO.
This fixes the out-of-bounds read without changing the handling of valid devices, and avoids silently truncating malformed protocol data.
--- drivers/gpu/drm/gud/gud_connector.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/gpu/drm/gud/gud_connector.c +5 -2
@@ -400,8 +400,11 @@ static int gud_connector_add_tv_mode(strfor (i =0 ; i < num_modes; i++) {char *mode = &buf[i *GUD_CONNECTOR_TV_MODE_NAME_LEN ]; -/* The device is not trusted to NUL-terminate the name */ - mode[GUD_CONNECTOR_TV_MODE_NAME_LEN -1 ] ='\0' ; +if (!memchr (mode,'\0' ,GUD_CONNECTOR_TV_MODE_NAME_LEN )) { + ret = -EIO ; + goto free; + } + modes[i] = mode; }
Greg Kroah-Hartman
maintainerPATCH 273/1376 drm/msm/dsi: round 6G byte clock rate to the PLL-achievable value
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kavan Smith <[email protected]>
commit 6cd33b6f4155efc20485929fd0b56bb704641db9 upstream.
MSM8916 runtime DSI commands still go through msm_dsi_host_xfer_prepare(), which re-applies the link clock rate before enabling the link clocks. That is fine in principle, but on DSI 6G the requested byte clock rate often does not exactly match the DSI PHY PLL's realizable rate. For example, the driver can request 56250000 Hz while the PLL actually runs at 56246337 Hz.
Because the requested and actual rates differ slightly, every later link_clk_set_rate() call is treated as a real clock change and re-locks the PLL. On a video-mode panel without an internal timing generator, such as samsung,s6d7aa0 / lsl080al03 on MSM8916, that live-clock glitch makes the panel lose pixel lock and visibly corrupts scanout on each runtime DCS command, including backlight writes.
Fix this by rounding the computed 6G byte clock rate up front, before it is stored in msm_host->byte_clk_rate and reused by later transfers. Once the host carries the PLL-achievable rate instead of the idealized one, repeated link_clk_set_rate() calls become no-ops in the common clock framework and no longer re-lock the PLL.
This keeps the normal transfer callback sequencing intact, preserves the OPP vote path in link_clk_set_rate(), and matches the fix direction suggested in the original 2018 discussion.
Patchwork: https://patchwork.freedesktop.org/patch/738234/
--- drivers/gpu/drm/msm/dsi/dsi_host.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
drivers/gpu/drm/msm/dsi/dsi_host.c +12 -0
@@ -621,12 +621,24 @@ static void dsi_calc_pclk(struct msm_dsiint dsi_calc_clk_rate_6g (struct msm_dsi_host *msm_host,bool is_bonded_dsi) { +long rounded_byte_clk_rate; +if (!msm_host->mode) {pr_err ("%s: mode not set\n" , __func__);return -EINVAL ; }dsi_calc_pclk (msm_host, is_bonded_dsi); + + rounded_byte_clk_rate =clk_round_rate (msm_host->byte_clk, + msm_host->byte_clk_rate); +if (rounded_byte_clk_rate <0 ) { +pr_err ("%s: failed to round byte clock rate, %ld\n" , + __func__, rounded_byte_clk_rate); +return rounded_byte_clk_rate; + } + + msm_host->byte_clk_rate = rounded_byte_clk_rate; msm_host->esc_clk_rate =clk_get_rate (msm_host->esc_clk);return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 274/1376 drm: Fix drm_crtc_commit leak if signaled when PAGE_FLIP_EVENT is used
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thadeu Lima de Souza Cascardo <[email protected]>
commit 4d4be202165e832d74849b4a68e289a2a377039c upstream.
Commit 1c6ceeee6ebb ("drm/atomic: Fix memleak on ERESTARTSYS during non-blocking commits") fixed a very similar issue when the event was allocated by drm_atomic_helper_setup_commit() itself.
However, if the event is allocated in prepare_signaling(), it will also be set to NULL in complete_signaling(), which prevents drm_crtc_commit from being put in __drm_atomic_helper_crtc_destroy_state().
Dropping the reference when the event is set to NULL at complete_signaling() fixes the leak.
The leak can be reproduced by sending a signal to the thread using DRM_MODE_PAGE_FLIP_EVENT and using a sw_sync fence to cause the atomic ioctl to block at drm_atomic_helper_wait_for_fences(). It happened both with amdgpu and vkms.
--- drivers/gpu/drm/drm_atomic_uapi.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/drm_atomic_uapi.c +2 -0
@@ -1327,6 +1327,8 @@ static void complete_signaling(struct dr* to prevent a double free in drm_atomic_state_clear. */ if (event && (event->base.fence || event->base.file_priv)) { +if (crtc_state->commit && crtc_state->commit->abort_completion) +drm_crtc_commit_put (crtc_state->commit);drm_event_cancel_free (dev, &event->base); crtc_state->event =NULL ; }
Greg Kroah-Hartman
maintainerPATCH 275/1376 drm/amdgpu: check thunderbolt before switcheroo registration
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Wang <[email protected]>
commit 8587d48d694da5aca580f92461658ec14470592b upstream.
Introduce a helper to consolidate the vga_switcheroo registration condition used by the init and fini paths.
Keep the explicit pci_is_thunderbolt_attached() check, as dev_is_removable() does not provide equivalent coverage for Thunderbolt-attached GPUs. This ensures such devices remain excluded from switcheroo registration while preserving the existing PX and Apple gmux handling.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +10 -4
@@ -4168,6 +4168,14 @@ static void amdgpu_device_set_mcbp(strucDRM_INFO ("MCBP is enabled\n" ); } +static bool +amdgpu_device_should_register_switcheroo (struct amdgpu_device *adev,bool px) +{ +return !pci_is_thunderbolt_attached (adev->pdev) && + (px || (!dev_is_removable (&adev->pdev->dev) && +apple_gmux_detect (NULL ,NULL ))); +} +/** * amdgpu_device_init - initialize the driver *
@@ -4628,8 +4636,7 @@ fence_driver_init: px =amdgpu_device_supports_px (ddev); -if (px || (!dev_is_removable (&adev->pdev->dev) && -apple_gmux_detect (NULL ,NULL ))) +if (amdgpu_device_should_register_switcheroo (adev, px))vga_switcheroo_register_client (adev->pdev, &amdgpu_switcheroo_ops, px);
@@ -4798,8 +4805,7 @@ void amdgpu_device_fini_sw(struct amdgpu px =amdgpu_device_supports_px (adev_to_drm (adev)); -if (px || (!dev_is_removable (&adev->pdev->dev) && -apple_gmux_detect (NULL ,NULL ))) +if (amdgpu_device_should_register_switcheroo (adev, px))vga_switcheroo_unregister_client (adev->pdev);if (px)
Greg Kroah-Hartman
maintainerPATCH 276/1376 drm/amdgpu: fix autosuspend cleanup during removal
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
commit ef5fcf2a6c320676bf8be2dadac93d9023b468b7 upstream.
amdgpu_pci_probe() calls pm_runtime_use_autosuspend(), but amdgpu_pci_remove() does not call the matching pm_runtime_dont_use_autosuspend().
If the autosuspend delay is set to a negative value while autosuspend is enabled, the runtime PM core increments usage_count to prevent runtime suspend. Without calling pm_runtime_dont_use_autosuspend() during teardown, this reference is not dropped and usage_count remains unbalanced.
The documentation for pm_runtime_use_autosuspend() also notes that it is important to undo it with pm_runtime_dont_use_autosuspend() at driver exit time, unless runtime PM was initially enabled with devm_pm_runtime_enable().
Add the missing pm_runtime_dont_use_autosuspend() call to the remove path.
This issue was found by manual code inspection.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +1 -0
@@ -2461,6 +2461,7 @@ amdgpu_pci_remove(struct pci_dev *pdev)if (adev->pm.rpm_mode !=AMDGPU_RUNPM_NONE ) {pm_runtime_get_sync (dev->dev);pm_runtime_forbid (dev->dev); +pm_runtime_dont_use_autosuspend (dev->dev); }amdgpu_driver_unload_kms (dev);
Greg Kroah-Hartman
maintainerPATCH 277/1376 drm/amdgpu: Skip accessing psp rum time db for APUs
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kanala Ramalingeswara Reddy <[email protected]>
commit a26301203a196a991527f7b1ab884d4dd0e7c95e upstream.
Psp runtime DB is for dGPUs only.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +6 -0
@@ -358,6 +358,12 @@ static bool psp_get_runtime_db_entry(strbool ret = false;int i; +/* +* Runtime DB is for dGPUs only. +*/ +if (adev->flags &AMD_IS_APU ) +return false; +if (amdgpu_ip_version (adev,MP0_HWIP ,0 ) ==IP_VERSION (13 ,0 ,6 ) ||amdgpu_ip_version (adev,MP0_HWIP ,0 ) ==IP_VERSION (13 ,0 ,14 ))return false;
Greg Kroah-Hartman
maintainerPATCH 278/1376 drm/amdgpu: use AMDGPU_GPU_PAGE_SHIFT instead of PAGE_SHIFT
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sunil Khatri <[email protected]>
commit d6e16df7df4d2c39e2b04b355d0434fb90e2d62c upstream.
For different address types the variable PAGE_SHIFT might not work well and it's better to use the GPU specific one
--- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +1 -1
@@ -1933,7 +1933,7 @@ int amdgpu_vm_bo_clear_mappings(struct a after->start = eaddr +1 ; after->last = tmp->last; after->offset = tmp->offset; - after->offset += (after->start - tmp->start) <<PAGE_SHIFT ; + after->offset += (after->start - tmp->start) <<AMDGPU_GPU_PAGE_SHIFT ; after->flags = tmp->flags; after->bo_va = tmp->bo_va;list_add (&after->list, &tmp->bo_va->invalids);
Greg Kroah-Hartman
maintainerPATCH 279/1376 drm/amdkfd: guard against NULL restore_mqd in CRIU queue restore
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vladimir Marioukhine <[email protected]>
commit 6aa530642f95d5c48aa336416f94a35e7949b647 upstream.
Both create_queue_cpsch() and create_queue_nocpsch() unconditionally call mqd_mgr->restore_mqd() when a CRIU restore is in progress (qd != NULL), with no NULL guard. On any system where restore_mqd is not implemented for the given queue type, a user holding CAP_CHECKPOINT_RESTORE can trigger a kernel NULL pointer dereference and panic the machine by issuing KFD_IOC_CRIU_OP_RESTORE with a crafted queue restore object. Note that checkpoint_mqd is likewise unimplemented on GFX12, so no legitimate CRIU image can reach this path — only a hand-crafted restore payload.
Add a NULL guard for restore_mqd immediately after mqd_mgr is resolved, unwinding via the existing error labels and returning -EOPNOTSUPP if the callback is not implemented. This mirrors the existing checkpoint_mqd guard in checkpoint_mqd().
--- drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +10 -0
@@ -617,6 +617,11 @@ static int create_queue_nocpsch(struct d mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type ( q->properties.type)]; +if (qd && !mqd_mgr->restore_mqd) { +pr_debug ("restore_mqd not implemented for this GPU\n" ); + retval = -EOPNOTSUPP ; + goto deallocate_vmid; + }if (q->properties.type ==KFD_QUEUE_TYPE_COMPUTE ) { retval =allocate_hqd (dqm, q);if (retval)
@@ -1967,6 +1972,11 @@ static int create_queue_cpsch(struct dev mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type ( q->properties.type)]; +if (qd && !mqd_mgr->restore_mqd) { +pr_debug ("restore_mqd not implemented for this GPU\n" ); + retval = -EOPNOTSUPP ; + goto out_deallocate_doorbell; + }if (q->properties.type ==KFD_QUEUE_TYPE_SDMA || q->properties.type ==KFD_QUEUE_TYPE_SDMA_XGMI )
Greg Kroah-Hartman
maintainerPATCH 280/1376 drm/amdkfd: Reject zero-sized AQL queue allocations after size halving
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sunday Clement <[email protected]>
commit 40ba09e11188d1b7f79d51fc28aca5ea45e0c138 upstream.
KFD_IOC_ALLOC_MEMORY_OF_GPU with flag KFD_IOC_ALLOC_MEM_FLAGS_AQL_QUEUE_MEM and size=1 triggers the AQL wraparound workaround (size >>= 1), reducing size to 0. The resulting zero passes through PAGE_ALIGN(0) = 0 without validation, bypassing the per-process VRAM quota check in reserve_mem_limit() (vram_used + 0 > vram_available is always false).
The fix adds post-halving zero-size validation in the primary allocation path (amdgpu_amdkfd_gpuvm.c). The check happens after size halving but before reserve_mem_limit(), and uses err_alignment_size error path to properly clean up the allocated kgd_mem structure and mutex.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c | 7 +++++++ drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +7 -0
@@ -1797,6 +1797,12 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_ size >>=1 ; aligned_size =PAGE_ALIGN (size); +/* reject AQL queue with size < 2 */ +if (!aligned_size) { + ret = -EINVAL ; + goto err_alignment_size; + } + (*mem)->alloc_flags = flags;amdgpu_sync_create (&(*mem)->sync);
@@ -1888,6 +1894,7 @@ err_bo_create:amdgpu_amdkfd_unreserve_mem_limit (adev, aligned_size, flags, xcp_id); err_reserve_limit:amdgpu_sync_free (&(*mem)->sync); +err_alignment_size:mutex_destroy (&(*mem)->lock);if (gobj)drm_gem_object_put (gobj);
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +2 -1
@@ -1167,7 +1167,8 @@ static int kfd_ioctl_alloc_memory_of_gpuif (flags &KFD_IOC_ALLOC_MEM_FLAGS_AQL_QUEUE_MEM ) size >>=1 ; -atomic64_add (PAGE_ALIGN (size), &pdd->vram_usage); + size =PAGE_ALIGN (size); +atomic64_add (size, &pdd->vram_usage); }mutex_unlock (&p->mutex);
Greg Kroah-Hartman
maintainerPATCH 281/1376 drm/nouveau: unsubscribe the channel-kill event before the fence context
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marek Czernohous <[email protected]>
commit 511585987d27d8cb668acebd399fc4deda23404c upstream.
nouveau_channel_del() tears the fence context down first and only drops the channel-kill subscription later, in the middle of the nvif object teardown:
if (chan->fence) nouveau_fence(chan->cli->drm)->context_del(chan); ... nvif_object_dtor(&chan->vram); nvif_event_dtor(&chan->kill);
The subscribed handler is nouveau_channel_killed(), which calls nouveau_channel_kill() and from there nouveau_fence_context_kill() on chan->fence. A kill event delivered in that window takes fctx->lock and walks fctx->pending on a fence context that context_del() has already freed.
Nothing reaches this below Fermi today, because the subscription is gated on FERMI_CHANNEL_GPFIFO and nothing kills a channel there. On Fermi and newer the window is real but narrow, since a kill has to land exactly while the channel is being destroyed. That is reason enough on its own, which is why this carries a Fixes: tag. The last patch in this series subscribes Tesla channels as well; nothing kills those today, so it does not widen the exposure now, but it is the groundwork for a recovery path that would, and the ordering is better fixed before that lands than alongside it.
Drop the subscription before anything it depends on is torn down.
--- drivers/gpu/drm/nouveau/nouveau_chan.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/gpu/drm/nouveau/nouveau_chan.c +8 -1
@@ -90,6 +90,14 @@ nouveau_channel_del(struct nouveau_chann {struct nouveau_channel *chan = *pchan;if (chan) { +/* +* Drop the kill-event subscription first. Its handler +* dereferences chan->fence, which the fence context teardown +* below frees, so leaving it armed across the teardown leaves +* a window for a use-after-free. +*/ +nvif_event_dtor (&chan->kill); +if (chan->fence)nouveau_fence (chan->cli->drm)->context_del (chan);
@@ -100,7 +108,6 @@ nouveau_channel_del(struct nouveau_channnvif_object_dtor (&chan->nvsw);nvif_object_dtor (&chan->gart);nvif_object_dtor (&chan->vram); -nvif_event_dtor (&chan->kill);nvif_object_dtor (&chan->user);nvif_mem_dtor (&chan->mem_userd);nvif_object_dtor (&chan->push.ctxdma);
Greg Kroah-Hartman
maintainerPATCH 282/1376 drm/nouveau: Use write-combined maps for coherent
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Faith Ekstrand <[email protected]>
commit 774b73428e6eabb4f0382aeeb76e569c7b106a29 upstream.
On Tegra devices, uncached maps translate to device memory, causing unaligned accesses by userspace resulting in a SIGBUS. Instead, use write-combined maps to ensure proper access.
This would also affect discrete cards on any Arm device. It was determined that discrete cards regardless of cpu arch should use write-combined maps for coherent anyways. Thus this change is made for all gpu types.
--- drivers/gpu/drm/nouveau/nouveau_sgdma.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/gpu/drm/nouveau/nouveau_sgdma.c +1 -3
@@ -72,9 +72,7 @@ nouveau_sgdma_create_ttm(struct ttm_buffstruct nouveau_sgdma_be *nvbe;enum ttm_caching caching; -if (nvbo->force_coherent) - caching = ttm_uncached; -else if (drm->agp.bridge) +if (nvbo->force_coherent || drm->agp.bridge) caching = ttm_write_combined;else caching = ttm_cached;
Greg Kroah-Hartman
maintainerPATCH 283/1376 drm/nouveau/uvmm: fix NULL deref unwinding an OP_MAP_SPARSE op
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhenhao Wan <[email protected]>
commit 412a6ceb56d501ef2f8202e26ab4b5d4dfbca566 upstream.
Each bind_job_op is zeroed by kzalloc_obj() in bind_job_op_from_uop(), and the OP_MAP_SPARSE case in nouveau_uvmm_bind_job_submit() only creates a region, so op->ops stays NULL for a successfully processed sparse map.
If a later op in the same job fails, the reverse unwind loop revisits that op and calls drm_gpuva_ops_free(&uvmm->base, op->ops) unconditionally. drm_gpuva_ops_free() dereferences its argument right away (list_for_each_entry_safe on &ops->list), so a NULL op->ops oopses. The path is reachable by any render-node fd holder, since NOUVEAU_VM_BIND is DRM_RENDER_ALLOW.
Guard the free with IS_ERR_OR_NULL(), as nouveau_uvmm_bind_job_cleanup() already does for the identical free.
--- drivers/gpu/drm/nouveau/nouveau_uvmm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/nouveau/nouveau_uvmm.c +2 -1
@@ -1418,7 +1418,8 @@ unwind:break ; } -drm_gpuva_ops_free (&uvmm->base, op->ops); +if (!IS_ERR_OR_NULL (op->ops)) +drm_gpuva_ops_free (&uvmm->base, op->ops); op->ops =NULL ; op->reg =NULL ; }
Greg Kroah-Hartman
maintainerPATCH 284/1376 drm/nouveau/uvmm: fix premature region free on failed OP_UNMAP_SPARSE
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhenhao Wan <[email protected]>
commit ccf930812f23b8259ef64fd3394d53b093e4651a upstream.
In nouveau_uvmm_bind_job_submit()'s OP_UNMAP_SPARSE arm, op->reg is set from nouveau_uvma_region_find(), which only looks the region up and takes no reference; a region's sole reference is its membership in uvmm->region_mt. Two failure paths leave op->reg set: the -ENOENT check when the region is busy, and the drm_gpuvm_sm_unmap_ops_create() failure. The sibling nouveau_uvmm_sm_unmap_prepare() failure just below clears op->reg; these two do not.
unwind_continue steps back one op, so the failing op is skipped by the unwind loop and its op->reg stays set. nouveau_uvmm_bind_job_cleanup() then enters its if (op->reg) branch and calls nouveau_uvma_region_remove() and nouveau_uvma_region_put() on it, dropping the tree's sole reference and freeing a region this job never created. The comment above the cleanup loop documents the broken invariant: op->reg must be NULL on submit failure.
This frees a live region on an unrelated failure, reachable single-job when drm_gpuvm_sm_unmap_ops_create() returns -ENOMEM; if another job owns the same region, its cleanup then removes and puts the freed region, a use-after-free. Clear op->reg on both failure paths.
--- drivers/gpu/drm/nouveau/nouveau_uvmm.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/nouveau/nouveau_uvmm.c +2 -0
@@ -1251,6 +1251,7 @@ nouveau_uvmm_bind_job_submit(struct nouv op->va.range);if (!op->reg || op->reg->dirty) { ret = -ENOENT ; + op->reg =NULL ; goto unwind_continue; }
@@ -1259,6 +1260,7 @@ nouveau_uvmm_bind_job_submit(struct nouv op->va.range);if (IS_ERR (op->ops)) { ret =PTR_ERR (op->ops); + op->reg =NULL ; goto unwind_continue; }
Greg Kroah-Hartman
maintainerPATCH 285/1376 drm/nouveau/uvmm: clear the dirty flag when unwinding an OP_UNMAP_SPARSE
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhenhao Wan <[email protected]>
commit 38a62306c4266bcb3cd89e33c7111ee33096ebb3 upstream.
A successful OP_UNMAP_SPARSE marks its region dirty with nouveau_uvma_region_dirty() and defers the teardown to nouveau_uvmm_bind_job_cleanup(); it does not remove the region from uvmm->region_mt.
If a later op in the job fails, the unwind path never clears reg->dirty (set in one place, cleared nowhere) and sets op->reg = NULL, so cleanup skips the teardown. The region is left in the tree with dirty set and its completion never signalled. Later binds over that range then fail permanently -- -ENOENT or -EINVAL from the dirty checks, or an unkillable wait_for_completion() in bind_validate_region() -- for the lifetime of the uvmm.
Clear reg->dirty when the unwind reverts the sparse unmap, restoring the region to the state it was found in.
--- drivers/gpu/drm/nouveau/nouveau_uvmm.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/nouveau/nouveau_uvmm.c +1 -0
@@ -1404,6 +1404,7 @@ unwind: op->va.range);break ;case OP_UNMAP_SPARSE : + op->reg->dirty = false;__nouveau_uvma_region_insert (uvmm, op->reg);nouveau_uvmm_sm_unmap_prepare_unwind (uvmm, &op->new, op->ops);
Greg Kroah-Hartman
maintainerPATCH 286/1376 afs: Fix leak of ungot volume
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
commit d672c276f685a540ed2b2a8bafaed4650a89022c upstream.
Fix afs_lookup_volume_rcu() so that it doesn't leak a dying volume if afs_try_get_volume() fails.
--- fs/afs/callback.c | 1 + 1 file changed, 1 insertion(+)
fs/afs/callback.c +1 -0
@@ -138,6 +138,7 @@ static struct afs_volume *afs_lookup_volif (volume &&afs_try_get_volume (volume, afs_volume_trace_get_callback))break ; + volume =NULL ;if (!need_seqretry (&cell->volume_lock, seq))break ; }
Greg Kroah-Hartman
maintainerPATCH 287/1376 xhci: fix lost bounce buffers on TDs spanning several ring segments
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arthur Gautier <[email protected]>
commit ff44dfb03a293bf30e31f98772a1dd316a6071d1 upstream.
When a TD reaches a link TRB with data that is not aligned to the endpoint's wMaxPacketSize, xhci_align_td() stages the unalignable tail through the bounce buffer of the ring segment holding that link TRB. xhci_unmap_td_bounce_buffer() later unmaps it and, for IN transfers, copies the data back into the URB's buffer.
The enqueue path records the segment that was bounced in td->bounce_seg, under the assumption that a TD never spans more than two ring segments. That assumption does not hold: a TD large enough to span three or more segments crosses several link TRBs and can be bounced at each of them. Only the last one survives in td->bounce_seg, so every earlier bounce buffer is neither copied back nor DMA unmapped.
The URB still completes with actual_length equal to the requested length and no error, so the transfer looks successful while a wMaxPacketSize sized hole in the destination buffer silently keeps its previous contents. It also leaks a DMA mapping per dropped bounce.
Any sufficiently large and fragmented bulk transfer can hit this. It was found with a USB mass storage device behind xHCI backing a dm-verity target with 512 byte hash blocks, where the stale data is detected rather than silently consumed. The device enumerates as SuperSpeed, so wMaxPacketSize is 1024, while dm-bufio issues one 512 byte bio per hash block. verity_prefetch_io() makes the block layer merge hundreds of them into a single request of up to 512 scatterlist entries of 512 bytes each. At 256 TRBs per ring segment such a TD spans three segments, and every segment boundary falls on an odd multiple of 512, i.e. unaligned to wMaxPacketSize. dm-bufio then caches a hash block holding stale data and dm-verity declares the metadata block corrupted:
device-mapper: verity: 8:2: metadata block 10850 is corrupted
A reproducer running this under qemu is available at
https://github.com/baloo/xhci-verity
The bounce state (bounce_buf, bounce_dma, bounce_len, bounce_offs) already lives on the ring segment, so there is nothing extra to track. Keep recording the last bounced segment in td->bounce_seg and, on completion, walk the segments from td->start_seg up to it, unmapping every segment that still has a pending bounce.
Stopping at td->bounce_seg rather than td->end_seg matters: a bounce implies the TD continues past that segment's link TRB, so bounce_seg is always strictly before end_seg, and a later TD may already have started in end_seg and been bounced there. Walking that far would copy a foreign bounce buffer into this URB and unmap it twice. It also keeps the walk correct if a TD ever wraps the whole ring so that end_seg == start_seg.
[mn: Add ring->num_segs check to prevent unlikely infinite for loop.]
--- drivers/usb/host/xhci-ring.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-)
drivers/usb/host/xhci-ring.c +24 -8
@@ -781,21 +781,18 @@ static void xhci_giveback_urb_in_irq(strusb_hcd_giveback_urb (hcd, urb, status); } -static void xhci_unmap_td_bounce_buffer (struct xhci_hcd *xhci, -struct xhci_ring *ring,struct xhci_td *td) +static void xhci_unmap_one_bounce_buffer (struct xhci_hcd *xhci, +struct xhci_ring *ring,struct xhci_td *td, +struct xhci_segment *seg) {struct device *dev =xhci_to_hcd (xhci)->self.sysdev; -struct xhci_segment *seg = td->bounce_seg;struct urb *urb = td->urb;size_t len; -if (!ring || !seg || !urb) -return ; -if (usb_urb_dir_out (urb)) {dma_unmap_single (dev, seg->bounce_dma, ring->bounce_buf_len,DMA_TO_DEVICE ); -return ; + goto done; } dma_unmap_single(dev, seg->bounce_dma, ring->bounce_buf_len,
@@ -811,10 +808,29 @@ static void xhci_unmap_td_bounce_buffer(memcpy (urb->transfer_buffer + seg->bounce_offs, seg->bounce_buf, seg->bounce_len); } +done: seg->bounce_len =0 ; seg->bounce_offs =0 ; } +static void xhci_unmap_td_bounce_buffer (struct xhci_hcd *xhci, +struct xhci_ring *ring,struct xhci_td *td) +{ +struct xhci_segment *seg; +int i =0 ; + +if (!td->bounce_seg || !ring || !td->urb) +return ; + +/* td->bounce_seg is the last one bounced, unmap them all */ +for (seg = td->start_seg; i++ < ring->num_segs; seg = seg->next) { +if (seg->bounce_len) +xhci_unmap_one_bounce_buffer (xhci, ring, td, seg); +if (seg == td->bounce_seg) +break ; + } +} +static int xhci_td_cleanup (struct xhci_hcd *xhci,struct xhci_td *td,struct xhci_ring *ep_ring,int status) {
@@ -3725,7 +3741,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd * &trb_buff_len, ring->enq_seg)) { send_addr = ring->enq_seg->bounce_dma; -/* assuming TD won't span 2 segs */ +/* TD bounced at least, and last on this seg */ td->bounce_seg = ring->enq_seg; } }
Greg Kroah-Hartman
maintainerPATCH 288/1376 ksmbd: zero pipe read compound padding
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
commit 73f860489e3be2245598d1819226304fc5b87291 upstream.
Compound response handling extends the last response iov to an eight-byte boundary.
smb2_read_pipe() allocates only the payload size, so the alignment padding can expose up to seven bytes of uninitialized kernel heap memory.
Allocate the aligned size and clear the unused tail before pinning the response buffer.
--- fs/smb/server/smb2pdu.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
fs/smb/server/smb2pdu.c +6 -1
@@ -6739,13 +6739,18 @@ static noinline int smb2_read_pipe(struc } aux_payload_buf = -kvmalloc (rpc_resp->payload_sz,KSMBD_DEFAULT_GFP ); +kvmalloc (ALIGN (rpc_resp->payload_sz,8 ), +KSMBD_DEFAULT_GFP );if (!aux_payload_buf) { err = -ENOMEM ; goto out; }memcpy (aux_payload_buf, rpc_resp->payload, rpc_resp->payload_sz); +if (rpc_resp->payload_sz &7 ) +memset (aux_payload_buf + rpc_resp->payload_sz,0 , +ALIGN (rpc_resp->payload_sz,8 ) - + rpc_resp->payload_sz); nbytes = rpc_resp->payload_sz; err = ksmbd_iov_pin_rsp_read(work, (void *)rsp,
Greg Kroah-Hartman
maintainerPATCH 289/1376 net/mlx5e: xsk: Fix unlocked writing to ICOSQ
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dragos Tatulea <[email protected]>
commit c326f9c68921e2f14dfcecb2f6b4216313d50248 upstream.
During napi poll, when the affinity changes and there's still XSK work to be done, we trigger an ICOSQ interrupt on the new CPU. However, this triggering on the ICOSQ is done unprotected.
There are 2 such races:
A) mlx5e_trigger_irq() is called while mlx5e_xsk_alloc_rx_mpwqe() is running from a different CPU due to affinity change. This can happen because IRQ triggering is done after napi_complete_done(). At this point the NAPI can be scheduled on a different CPU. Like this:
CPU A (old affinity, NAPI tail) CPU B (new affinity, fresh NAPI)
------------------------------- --------------------------------
napi_complete_done() clears SCHED
mlx5e_cq_arm(...)
napi_schedule_prep() sets SCHED
mlx5e_napi_poll()
mlx5e_xsk_alloc_rx_mpwqe()
mlx5e_icosq_sync_lock() // noop
memcpy 640 B UMR body
advance sq->pc by 10
mlx5e_trigger_irq(&c->icosq)
wqe_info[pi] = {NOP, 1}
mlx5e_post_nop() advances sq->pcB) mlx5e_trigger_irq() is called on the ICOSQ when mlx5e_trigger_napi_icosq() is running.
The obvious fix would be to lock the ICOSQ. But ICOSQ has an optimized locking scheme that doesn't work for this scenario. Kick the async ICOSQ instead which is always locked.
This issue was noticed in the wild with the following splat:
netdevice: ge-0-0-1: Bad OP in ICOSQ CQE: 0xd
WARNING: drivers/net/ethernet/mellanox/mlx5/core/en_rx.c:826 [...] [...] Call Trace: <IRQ> mlx5e_napi_poll+0x11d/0x7f0 [mlx5_core] __napi_poll+0x30/0x200 ? skb_defer_free_flush+0x9c/0xc0 net_rx_action+0x2fe/0x3f0 handle_softirqs+0xd8/0x340 __irq_exit_rcu+0xbc/0xe0 common_interrupt+0x85/0xa0 </IRQ> <TASK> asm_common_interrupt+0x26/0x40 [...] ---[ end trace 0000000000000000 ]--- mlx5_core 0000:08:00.0 ge-0-0-1: Error cqe on cqn 0x548, ci 0x2022, qn 0x8f4, opcode 0xd, syndrome 0x2, vendor syndrome 0x68 00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000030: 00 00 00 00 01 00 68 02 01 00 08 f4 de 14 59 d2 WQE DUMP: WQ size 16384 WQ cur size 0, WQE index 0x1e14, len: 64 00000000: 00 00 00 01 d9 ed 80 02 00 00 00 01 d9 ed 90 02 00000010: 00 00 00 01 d9 ed a0 02 00 00 00 01 d9 ed b0 02 00000020: 00 00 00 01 d9 ed c0 02 00 00 00 01 d9 ed d0 02 00000030: 00 00 00 01 d9 ed e0 02 00 00 00 01 d9 ed f0 02 mlx5_core 0000:08:00.0 ge-0-0-1: Error cqe on cqn 0x548, ci 0x2023, qn 0x8f4, opcode 0xd, syndrome 0x5, vendor syndrome 0xf9 00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000030: 00 00 00 00 01 00 f9 05 01 00 08 f4 de 15 cf d2
[ Backport to 6.18.y and older: upstream commit calls
mlx5e_trigger_napi_async_icosq(), which was introduced by commit 0da1dba72616 ("net/mlx5e: XSK, Fix unintended ICOSQ change") and is not present here. In these trees mlx5e_trigger_napi_icosq() is the equivalent helper: it takes c->async_icosq_lock and triggers c->async_icosq, which is unconditionally opened, activated, polled and armed for every channel. Race B does not apply, as it concerns the sync-ICOSQ variant of mlx5e_trigger_napi_icosq() that only exists upstream, and mlx5e_icosq_sync_lock() in the race A diagram has no equivalent here. ]
--- drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c +1 -1
@@ -245,7 +245,7 @@ int mlx5e_napi_poll(struct napi_struct *napi, int budget) }if (unlikely (aff_change && busy_xsk)) { -mlx5e_trigger_irq (&c->icosq); +mlx5e_trigger_napi_icosq (c); ch_stats->force_irq++; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 290/1376 nvmet-auth: Synchronize timeout work during SQ teardown
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kazuki Hanai <[email protected]>
[ Upstream commit eaa948c0e19b1bb2d93262207bca0c3d19cc3406 ]
nvmet_auth_sq_free() cancels auth_expired_work with cancel_delayed_work(). If the work has already started, cancellation does not wait for the callback. Transport teardown can consequently free or reuse the queue containing struct nvmet_sq while nvmet_auth_expired_work() still accesses that SQ.
Add a teardown-specific helper that synchronously drains the delayed work before freeing authentication state, and use it from nvmet_sq_destroy(). Keep the non-synchronous helper for in-band authentication state cleanup, where the SQ owner remains alive.
--- drivers/nvme/target/auth.c | 6 ++++++ drivers/nvme/target/core.c | 2 +- drivers/nvme/target/nvmet.h | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-)
drivers/nvme/target/auth.c +6 -0
@@ -241,6 +241,12 @@ void nvmet_auth_sq_free(struct nvmet_sq *sq) sq->dhchap_skey =NULL ; } +void nvmet_auth_sq_destroy (struct nvmet_sq *sq) +{ +cancel_delayed_work_sync (&sq->auth_expired_work); +nvmet_auth_sq_free (sq); +} +void nvmet_destroy_auth (struct nvmet_ctrl *ctrl) { ctrl->shash_id =0 ;
drivers/nvme/target/core.c +1 -1
@@ -812,7 +812,7 @@ void nvmet_sq_destroy(struct nvmet_sq *sq)wait_for_completion (&sq->confirm_done);wait_for_completion (&sq->free_done);percpu_ref_exit (&sq->ref); -nvmet_auth_sq_free (sq); +nvmet_auth_sq_destroy (sq);/* * we must reference the ctrl again after waiting for inflight IO
drivers/nvme/target/nvmet.h +2 -0
@@ -737,6 +737,7 @@ u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl);void nvmet_auth_sq_init (struct nvmet_sq *sq);void nvmet_destroy_auth (struct nvmet_ctrl *ctrl);void nvmet_auth_sq_free (struct nvmet_sq *sq); +void nvmet_auth_sq_destroy (struct nvmet_sq *sq);int nvmet_setup_dhgroup (struct nvmet_ctrl *ctrl,u8 dhgroup_id);bool nvmet_check_auth_status (struct nvmet_req *req); int nvmet_auth_host_hash(struct nvmet_req *req, u8 *response,
@@ -761,6 +762,7 @@ static inline void nvmet_auth_sq_init(struct nvmet_sq *sq) }static inline void nvmet_destroy_auth (struct nvmet_ctrl *ctrl) {};static inline void nvmet_auth_sq_free (struct nvmet_sq *sq) {}; +static inline void nvmet_auth_sq_destroy (struct nvmet_sq *sq) {};static inline bool nvmet_check_auth_status (struct nvmet_req *req) {return true;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 291/1376 mm/damon/vaddr: drop last same folio access check optimization
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: SJ Park <[email protected]>
[ Upstream commit 831846078caa14b7d00b2ccca8b8fe522afe3204 ]
The optimization can race when multiple kdamonds are running. Meanwhile, the impact of the optimization is quite doubtful. Just remove it.
The user impact of the issue should be quite trivial. After all, the race can happen only when the user intentionally setup DAMON in the way. Even if it happens, it would be rare and only degrade the best-effort monitoring results. No critical consequences like kernel panic or memory corruption happen.
The race possibility was discovered [1] by Sashiko.
--- mm/damon/vaddr.c | 34 ++++++---------------------------- 1 file changed, 6 insertions(+), 28 deletions(-)
mm/damon/vaddr.c +6 -28
@@ -429,8 +429,6 @@ static void damon_va_prepare_access_checks(struct damon_ctx *ctx) }struct damon_young_walk_private { -/* size of the folio for the access checked virtual memory address */ -unsigned long *folio_sz;bool young; };
@@ -466,7 +464,6 @@ static int damon_young_pmd_entry(pmd_t *pmd, unsigned long addr,mmu_notifier_test_young (walk->mm, addr)) priv->young = true; - *priv->folio_sz =HPAGE_PMD_SIZE ;folio_put (folio); huge_out:spin_unlock (ptl);
@@ -488,7 +485,6 @@ static int damon_young_pmd_entry(pmd_t *pmd, unsigned long addr,if (pte_young (ptent) || !folio_test_idle (folio) ||mmu_notifier_test_young (walk->mm, addr)) priv->young = true; - *priv->folio_sz =folio_size (folio);folio_put (folio); out:pte_unmap_unlock (pte, ptl);
@@ -517,7 +513,6 @@ static int damon_young_hugetlb_entry(pte_t *pte, unsigned long hmask,if (pte_young (entry) || !folio_test_idle (folio) ||mmu_notifier_test_young (walk->mm, addr)) priv->young = true; - *priv->folio_sz =huge_page_size (h);folio_put (folio);
@@ -535,11 +530,9 @@ static const struct mm_walk_ops damon_young_ops = { .walk_lock = PGWALK_RDLOCK, }; -static bool damon_va_young (struct mm_struct *mm,unsigned long addr, -unsigned long *folio_sz) +static bool damon_va_young (struct mm_struct *mm,unsigned long addr) {struct damon_young_walk_private arg = { - .folio_sz = folio_sz, .young = false, };
@@ -556,29 +549,18 @@ static bool damon_va_young(struct mm_struct *mm, unsigned long addr,* r the region to be checked */ static void __damon_va_check_access (struct mm_struct *mm, -struct damon_region *r,bool same_target, +struct damon_region *r,struct damon_attrs *attrs) { -static unsigned long last_addr; -static unsigned long last_folio_sz =PAGE_SIZE ; -static bool last_accessed; +bool accessed;if (!mm) {damon_update_region_access_rate (r, false, attrs);return ; } -/* If the region is in the last checked page, reuse the result */ -if (same_target && (ALIGN_DOWN (last_addr, last_folio_sz) == -ALIGN_DOWN (r->sampling_addr, last_folio_sz))) { -damon_update_region_access_rate (r, last_accessed, attrs); -return ; - } - - last_accessed =damon_va_young (mm, r->sampling_addr, &last_folio_sz); -damon_update_region_access_rate (r, last_accessed, attrs); - - last_addr = r->sampling_addr; + accessed =damon_va_young (mm, r->sampling_addr); +damon_update_region_access_rate (r, accessed, attrs); }static unsigned int damon_va_check_accesses (struct damon_ctx *ctx)
@@ -587,16 +569,12 @@ static unsigned int damon_va_check_accesses(struct damon_ctx *ctx)struct mm_struct *mm;struct damon_region *r;unsigned int max_nr_accesses =0 ; -bool same_target;damon_for_each_target (t, ctx) { mm =damon_get_mm (t); - same_target = false;damon_for_each_region (r, t) { -__damon_va_check_access (mm, r, same_target, - &ctx->attrs); +__damon_va_check_access (mm, r, &ctx->attrs); max_nr_accesses =max (r->nr_accesses, max_nr_accesses); - same_target = true; }if (mm)mmput (mm);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 292/1376 mm/damon/ops-common: use nr_accesses moving sum for quota score
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: SJ Park <[email protected]>
[ Upstream commit 6c25083f7ae7e2660d766169e5b4d3e96010503f ]
Since commit 42f994b71404 ("mm/damon/core: implement scheme-specific apply interval"), DAMOS scheme can be applied at any time. At that time, nr_accesses may not be fully aggregated. But the quota prioritization score is calculated using the not fully aggregated count. As a result, the performance of DAMOS could be degraded. Fix by using damon_nr_accesses_mvsum() instead.
The user impact of the issue is suboptimum DAMOS performance under certain setups. Nonetheless, the bug was there from the beginning of the setup availability. In other words, the suboptimum performance is the baseline of the setup and hence it didn't cause regression. Also the extent of the suboptimality was not big enough to be found from users and testers. Still, this is a clear bug that is better to be fixed, and can be easily fixed.
--- mm/damon/ops-common.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
mm/damon/ops-common.c +3 -2
@@ -80,8 +80,9 @@ int damon_hot_score(struct damon_ctx *c, struct damon_region *r,unsigned int age_weight = s->quota.weight_age;int hotness; - freq_subscore = r->nr_accesses *DAMON_MAX_SUBSCORE / -damon_max_nr_accesses (&c->attrs); + freq_subscore =mult_frac (r->nr_accesses_bp /10000 , +DAMON_MAX_SUBSCORE , +damon_max_nr_accesses (&c->attrs)); age_in_sec = (unsigned long )r->age * c->attrs.aggr_interval /1000000 ; for (age_in_log = 0; age_in_log < DAMON_MAX_AGE_IN_LOG && age_in_sec;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 293/1376 mm/damon/paddr: drop last same folio access check reuse optimization
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: SJ Park <[email protected]>
[ Upstream commit f23f0aa62b2f32c2b12f95959fc4603ef81678b2 ]
It can race when multiple kdamonds are being used. The problem from the race is doubtful, but the gain from the optimization is also doubtful. Simply drop the optimization in favor of code simplicity.
The user impact is doubtfully trivial. After all, this kind of interference can happen only by intentional user setup. Even if it happens, it will be rare, and the consequence is degradation of the best-effort monitoring results. No critical consequences like kernel panic or memory corruption happen.
The race was discovered [1] by Sashiko.
--- mm/damon/paddr.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-)
mm/damon/paddr.c +4 -16
@@ -148,7 +148,7 @@ static bool damon_folio_young(struct folio *folio)return accessed; } -static bool damon_pa_young (unsigned long paddr,unsigned long *folio_sz) +static bool damon_pa_young (unsigned long paddr) {struct folio *folio =damon_get_folio (PHYS_PFN (paddr));bool accessed;
@@ -157,7 +157,6 @@ static bool damon_pa_young(unsigned long paddr, unsigned long *folio_sz)return false; accessed =damon_folio_young (folio); - *folio_sz =folio_size (folio);folio_put (folio);return accessed; }
@@ -165,21 +164,10 @@ static bool damon_pa_young(unsigned long paddr, unsigned long *folio_sz)static void __damon_pa_check_access (struct damon_region *r,struct damon_attrs *attrs) { -static unsigned long last_addr; -static unsigned long last_folio_sz =PAGE_SIZE ; -static bool last_accessed; - -/* If the region is in the last checked page, reuse the result */ -if (ALIGN_DOWN (last_addr, last_folio_sz) == -ALIGN_DOWN (r->sampling_addr, last_folio_sz)) { -damon_update_region_access_rate (r, last_accessed, attrs); -return ; - } - - last_accessed =damon_pa_young (r->sampling_addr, &last_folio_sz); -damon_update_region_access_rate (r, last_accessed, attrs); +bool accessed; - last_addr = r->sampling_addr; + accessed =damon_pa_young (r->sampling_addr); +damon_update_region_access_rate (r, accessed, attrs); }static unsigned int damon_pa_check_accesses (struct damon_ctx *ctx)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 294/1376 mm/damon/vaddr-kunit: check region count in three_regions test
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: SJ Park <[email protected]>
[ Upstream commit 5fea07e460874c8c7cf00f728efbe22abc62c8d8 ]
damon_do_test_apply_three_regions() iterates regions after damon_set_regions() call assuming the function would succeed at setting the number of regions the same to the expected one. It might have failed. In this case, __nth_region_of() in the iteration could return NULL and NULL dereference can happen in the test.
The consequent user impact (NULL dereference) is quite bad. The realistic user impact would be limited, though. It would affect only test run setups.
Fix it by testing if the number of regions was also changed as expected and exit early for the failure.
The issue was discovered [1] by Sashiko.
--- mm/damon/tests/vaddr-kunit.h | 5 +++++ 1 file changed, 5 insertions(+)
mm/damon/tests/vaddr-kunit.h +5 -0
@@ -149,12 +149,17 @@ static void damon_do_test_apply_three_regions(struct kunit *test,damon_set_regions (t, three_regions,3 ); +KUNIT_EXPECT_EQ (test,damon_nr_regions (t), nr_expected /2 ); +if (damon_nr_regions (t) != nr_expected /2 ) + goto out; +for (i =0 ; i < nr_expected /2 ; i++) { r =__nth_region_of (t, i);KUNIT_EXPECT_EQ (test, r->ar.start, expected[i *2 ]);KUNIT_EXPECT_EQ (test, r->ar.end, expected[i *2 +1 ]); } +out:damon_destroy_target (t); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 295/1376 mm/damon/core-kunit: handle region split failure in filter_out()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: SJ Park <[email protected]>
[ Upstream commit 3423fe70395210e2f0cd795270292f6a27cd57b5 ]
damos_test_filter_out() test checks if damos_filter_match() of an address filter splits the region as expected under a given condition. But, the test continued regardless of the split successes. As a result, the later part of the test could dereference invalid pointers that returned from damon_next_region(). Further, it could corrupt memory from damon_destroy_region().
The consequent user impact (memory corruption) is quite bad. The realistic user impact would be limited, though. It would affect only test run setups.
Fix it by exiting early for the number of regions test failure.
The issue was discovered [1] by Sashiko.
--- mm/damon/tests/core-kunit.h | 5 +++++ 1 file changed, 5 insertions(+)
mm/damon/tests/core-kunit.h +5 -0
@@ -557,6 +557,8 @@ static void damos_test_filter_out(struct kunit *test)KUNIT_EXPECT_EQ (test, r->ar.start,DAMON_MIN_REGION *1 );KUNIT_EXPECT_EQ (test, r->ar.end,DAMON_MIN_REGION *2 );KUNIT_EXPECT_EQ (test,damon_nr_regions (t),2 ); +if (damon_nr_regions (t) !=2 ) + goto out; r2 =damon_next_region (r);KUNIT_EXPECT_EQ (test, r2->ar.start,DAMON_MIN_REGION *2 );KUNIT_EXPECT_EQ (test, r2->ar.end,DAMON_MIN_REGION *4 );
@@ -570,11 +572,14 @@ static void damos_test_filter_out(struct kunit *test)KUNIT_EXPECT_EQ (test, r->ar.start,DAMON_MIN_REGION *2 );KUNIT_EXPECT_EQ (test, r->ar.end,DAMON_MIN_REGION *6 );KUNIT_EXPECT_EQ (test,damon_nr_regions (t),2 ); +if (damon_nr_regions (t) !=2 ) + goto out; r2 =damon_next_region (r);KUNIT_EXPECT_EQ (test, r2->ar.start,DAMON_MIN_REGION *6 );KUNIT_EXPECT_EQ (test, r2->ar.end,DAMON_MIN_REGION *8 );damon_destroy_region (r2, t); +out:damon_free_target (t);damos_free_filter (f); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 296/1376 mm/damon/tests/core-kunit: catch test failure in test_merge_regions_of()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: SJ Park <[email protected]>
[ Upstream commit b640708929aa956235866bf7717d89018c661083 ]
KUNIT_EXPECT_EQ() does not abort the execution of test code when the expectation is not met. But damon_test_merge_regions_of() code after its initial KUNIT_EXPECT_EQ() call assumes the expectation is met. It does a per-region test with a hard-coded number of regions that is correct only if the expectation was met. As a result, __nth_region_of() could return NULL, and the test code can dereference NULL pointers. Fix the issue by catching the expectation failure and skip the per-region tests.
The user impact on realistic setups should be negligible, as it is a unit test.
The issue was discovered [1] by Sashiko.
--- mm/damon/tests/core-kunit.h | 3 +++ 1 file changed, 3 insertions(+)
mm/damon/tests/core-kunit.h +3 -0
@@ -269,11 +269,14 @@ static void damon_test_merge_regions_of(struct kunit *test)damon_merge_regions_of (t,9 ,9999 );/* 0-112, 114-130, 130-156, 156-170 */ KUNIT_EXPECT_EQ (test,damon_nr_regions (t),5u ); +if (damon_nr_regions (t) !=5 ) + goto out;for (i =0 ; i <5 ; i++) { r =__nth_region_of (t, i);KUNIT_EXPECT_EQ (test, r->ar.start, saddrs[i]);KUNIT_EXPECT_EQ (test, r->ar.end, eaddrs[i]); } +out:damon_free_target (t); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 297/1376 of: unittest: Fix memory leak in unittest_data_add()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zilin Guan <[email protected]>
[ Upstream commit 235a1eb8d2dcc49a6cf0a5ee1aa85544a5d0054b ]
In unittest_data_add(), if of_resolve_phandles() fails, the allocated unittest_data is not freed, leading to a memory leak.
Fix this by using scope-based cleanup helper __free(kfree) for automatic resource cleanup. This ensures unittest_data is automatically freed when it goes out of scope in error paths.
For the success path, use retain_and_null_ptr() to transfer ownership of the memory to the device tree and prevent double freeing.
--- drivers/of/unittest.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-)
drivers/of/unittest.c +3 -5
@@ -1871,7 +1871,6 @@ static void attach_node_and_children(struct device_node *np)*/ static int __init unittest_data_add (void ) { -void *unittest_data;void *unittest_data_align;struct device_node *unittest_data_node =NULL , *np;/*
@@ -1890,7 +1889,7 @@ static int __init unittest_data_add(void) }/* creating copy */ - unittest_data =kmalloc (size +FDT_ALIGN_SIZE ,GFP_KERNEL ); + void *unittest_data __free(kfree) = kmalloc(size + FDT_ALIGN_SIZE, GFP_KERNEL);if (!unittest_data)return -ENOMEM ;
@@ -1900,12 +1899,10 @@ static int __init unittest_data_add(void) ret =of_fdt_unflatten_tree (unittest_data_align,NULL , &unittest_data_node);if (!ret) {pr_warn ("%s: unflatten testcases tree failed\n" , __func__); -kfree (unittest_data);return -ENODATA ; }if (!unittest_data_node) {pr_warn ("%s: testcases tree is empty\n" , __func__); -kfree (unittest_data);return -ENODATA ; }
@@ -1924,7 +1921,6 @@ static int __init unittest_data_add(void)/* attach the sub-tree to live tree */ if (!of_root) {pr_warn ("%s: no live tree to attach sub-tree\n" , __func__); -kfree (unittest_data); rc = -ENODEV ; goto unlock; }
@@ -1945,6 +1941,8 @@ static int __init unittest_data_add(void)EXPECT_END (KERN_INFO ,"Duplicate name in testcase-data, renamed to \"duplicate-name#1\"" ); +retain_and_null_ptr (unittest_data); + unlock:of_overlay_mutex_unlock ();
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 298/1376 ksmbd: fix use-after-free in smb2_open during durable reconnect
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Akif <[email protected]>
[ Upstream commit 1baff47b81f94f9231c91236aa511420d0e266b9 ]
In smb2_open, the call to ksmbd_put_durable_fd(fp) drops the reference to the durable file descriptor early during the durable reconnect process. If an error occurs subsequently (eg, ksmbd_iov_pin_rsp fails) or a scavenger accesses the file, it leads to a use-after-free when accessing fp properties (eg fp->create_time).
Move the single put to the end of the function below err_out2 so fp stays valid until smb2_open returns.
--- fs/smb/server/smb2pdu.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-)
fs/smb/server/smb2pdu.c +5 -8
@@ -3018,29 +3018,23 @@ int smb2_open(struct ksmbd_work *work)if (dh_info.reconnected == true) { rc =smb2_check_durable_oplock (conn, share, dh_info.fp, lc, sess->user, name); -if (rc) { -ksmbd_put_durable_fd (dh_info.fp); +if (rc) goto err_out2; - } rc =ksmbd_reopen_durable_fd (work, dh_info.fp); -if (rc) { -ksmbd_put_durable_fd (dh_info.fp); +if (rc) goto err_out2; - } fp = dh_info.fp;if (ksmbd_override_fsids (work)) { rc = -ENOMEM ; -ksmbd_put_durable_fd (dh_info.fp); goto err_out2; } file_info =FILE_OPENED ; rc =ksmbd_vfs_getattr (&fp->filp->f_path, &stat); -ksmbd_put_durable_fd (fp);if (rc) goto err_out2;
@@ -3810,6 +3804,9 @@ int smb2_open(struct ksmbd_work *work)ksmbd_debug (SMB ,"Error response: %x\n" , rsp->hdr.Status); } +if (dh_info.reconnected) +ksmbd_put_durable_fd (dh_info.fp); +kfree (name);kfree (lc);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 299/1376 ksmbd: fix durable reconnect error path file lifetime
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Junyi Liu <[email protected]>
[ Upstream commit 3515503322f4819277091839eed46b695096aca5 ]
After a durable reconnect succeeds, ksmbd_reopen_durable_fd() republishes the same ksmbd_file into the session volatile-id table. If smb2_open() then takes a later error path, cleanup first calls ksmbd_fd_put(work, fp) and then unconditionally calls ksmbd_put_durable_fd(dh_info.fp).
In this case fp and dh_info.fp are the same object. The first put drops the reconnect lookup reference, but the final durable put can run __ksmbd_close_fd(NULL, fp). Because the final close is not session-aware, it can free the file object without removing the volatile-id entry that was just published into the session table.
Use the session-aware put for the final reconnect drop when the reconnect had already succeeded and the error path is cleaning up the republished file. Earlier reconnect failures, before fp is assigned to dh_info.fp, keep using the durable-only put path.
--- fs/smb/server/smb2pdu.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-)
fs/smb/server/smb2pdu.c +13 -2
@@ -3804,8 +3804,19 @@ int smb2_open(struct ksmbd_work *work)ksmbd_debug (SMB ,"Error response: %x\n" , rsp->hdr.Status); } -if (dh_info.reconnected) -ksmbd_put_durable_fd (dh_info.fp); +if (dh_info.reconnected) { +/* +* If reconnect succeeded, fp was republished in the +* session file table. On a later error, ksmbd_fd_put() +* above drops the session reference; drop the durable +* lookup reference through the same session-aware path so +* final close removes the volatile id before freeing fp. +*/ +if (rc && fp == dh_info.fp) +ksmbd_fd_put (work, dh_info.fp); +else +ksmbd_put_durable_fd (dh_info.fp); + }kfree (name);kfree (lc);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 300/1376 ksmbd: fix FSCTL permission bypass by adding a permission check for FSCTL_SET_SPARSE
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Shen <[email protected]>
[ Upstream commit cc57232cae23c0df91b4a59d0f519141ce9b5b02 ]
FSCTL_SET_SPARSE in fsctl_set_sparse() modifies the file's sparse attribute and saves it through xattr without any permission checks.
This exposes two issues:
1) A client on a read-only share can change the sparse attribute on files it opened, even though the share is read-only. Other FSCTL write operations already check test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE), but FSCTL_SET_SPARSE does not.
2) Even on writable shares, clients without FILE_WRITE_DATA or FILE_WRITE_ATTRIBUTES access should not modify the sparse attribute. Similar handle-level checks exist in other functions but are missing here.
Add both share-level writable check and per-handle access check. Use goto out on error to avoid leaking file references.
--- fs/smb/server/smb2pdu.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
fs/smb/server/smb2pdu.c +11 -0
@@ -8206,9 +8206,20 @@ static inline int fsctl_set_sparse(struct ksmbd_work *work, u64 id,int ret =0 ;__le32 old_fattr; +if (!test_tree_conn_flag (work->tcon,KSMBD_TREE_CONN_FLAG_WRITABLE )) { +ksmbd_debug (SMB ,"User does not have write permission\n" ); +return -EACCES ; + } + fp =ksmbd_lookup_fd_fast (work, id);if (!fp)return -ENOENT ; + +if (!(fp->daccess & (FILE_WRITE_DATA_LE |FILE_WRITE_ATTRIBUTES_LE ))) { + ret = -EACCES ; + goto out; + } + idmap =file_mnt_idmap (fp->filp); old_fattr = fp->f_ci->m_fattr;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 301/1376 batman-adv: dat: atomically update mac addresses
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit e6de568d3eda3e3c01c868fabd7a9535d5ee4a73 upstream.
When a MAC address is updated in batadv_dat_entry_add(), it is done using a simple copy function. A parallel reader might only see parts of this update. In worst case, the reader is transporting the half updated MAC address over the network or is creating an ARP response using it - poisoning the ARP cache.
atomic64_t can be used to store the 48 bit of a mac address. A reader will then either see the old mac address or the new one - never a mixture of both.
--- net/batman-adv/distributed-arp-table.c | 58 +++++++++++++++++--------- net/batman-adv/types.h | 2 +- 2 files changed, 40 insertions(+), 20 deletions(-)
net/batman-adv/distributed-arp-table.c +39 -19
@@ -376,18 +376,19 @@ batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip,static void batadv_dat_entry_add (struct batadv_priv *bat_priv,__be32 ip,u8 *mac_addr,unsigned short vid) { +u64 u64_mac =ether_addr_to_u64 (mac_addr);struct batadv_dat_entry *dat_entry;int hash_added; dat_entry =batadv_dat_entry_hash_find (bat_priv, ip, vid);/* if this entry is already known, just update it */ if (dat_entry) { -if (!batadv_compare_eth (dat_entry->mac_addr, mac_addr)) -ether_addr_copy (dat_entry->mac_addr, mac_addr); +atomic64_set (&dat_entry->mac_addr, u64_mac); + dat_entry->last_update = jiffies;batadv_dbg (BATADV_DBG_DAT , bat_priv,"Entry updated: %pI4 %pM (vid: %d)\n" , - &dat_entry->ip, dat_entry->mac_addr, + &dat_entry->ip, mac_addr,batadv_print_vid (vid)); goto out; }
@@ -398,7 +399,7 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip, dat_entry->ip = ip; dat_entry->vid = vid; -ether_addr_copy (dat_entry->mac_addr, mac_addr); +atomic64_set (&dat_entry->mac_addr, u64_mac); dat_entry->last_update = jiffies;kref_init (&dat_entry->refcount);
@@ -414,7 +415,7 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip, }batadv_dbg (BATADV_DBG_DAT , bat_priv,"New entry added: %pI4 %pM (vid: %d)\n" , - &dat_entry->ip, dat_entry->mac_addr,batadv_print_vid (vid)); + &dat_entry->ip, mac_addr,batadv_print_vid (vid)); out:batadv_dat_entry_put (dat_entry);
@@ -869,6 +870,8 @@ batadv_dat_cache_dump_entry(struct sk_buff *msg, u32 portid,struct netlink_callback *cb, struct batadv_dat_entry *dat_entry) { + u8 mac[ETH_ALEN]; +u64 u64_mac;int msecs;void *hdr;
@@ -881,11 +884,12 @@ batadv_dat_cache_dump_entry(struct sk_buff *msg, u32 portid,genl_dump_check_consistent (cb, hdr); msecs =jiffies_to_msecs (jiffies - dat_entry->last_update); + u64_mac =atomic64_read (&dat_entry->mac_addr); +u64_to_ether_addr (u64_mac, mac);if (nla_put_in_addr (msg,BATADV_ATTR_DAT_CACHE_IP4ADDRESS , dat_entry->ip) || -nla_put (msg,BATADV_ATTR_DAT_CACHE_HWADDRESS ,ETH_ALEN , - dat_entry->mac_addr) || +nla_put (msg,BATADV_ATTR_DAT_CACHE_HWADDRESS ,ETH_ALEN , mac) ||nla_put_u16 (msg,BATADV_ATTR_DAT_CACHE_VID , dat_entry->vid) ||nla_put_u32 (msg,BATADV_ATTR_LAST_SEEN_MSECS , msecs)) {genlmsg_cancel (msg, hdr);
@@ -1161,6 +1165,8 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,struct net_device *soft_iface = bat_priv->soft_iface;int hdr_size =0 ;unsigned short vid; +u8 mac[ETH_ALEN ]; +u64 u64_mac;if (!atomic_read (&bat_priv->distributed_arp_table)) goto out;
@@ -1188,6 +1194,9 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv, dat_entry =batadv_dat_entry_hash_find (bat_priv, ip_dst, vid);if (dat_entry) { + u64_mac =atomic64_read (&dat_entry->mac_addr); +u64_to_ether_addr (u64_mac, mac); +/* If the ARP request is destined for a local client the local * client will answer itself. DAT would only generate a * duplicate packet.
@@ -1196,7 +1205,7 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,* additional DAT answer may trigger kernel warnings about * a packet coming from the wrong port. */ -if (batadv_is_my_client (bat_priv, dat_entry->mac_addr, vid)) { +if (batadv_is_my_client (bat_priv, mac, vid)) { ret = true; goto out; }
@@ -1206,18 +1215,16 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,* the backbone gws belonging to our backbone has claimed the * destination. */ -if (!batadv_bla_check_claim (bat_priv, - dat_entry->mac_addr, vid)) { +if (!batadv_bla_check_claim (bat_priv, mac, vid)) {batadv_dbg (BATADV_DBG_DAT , bat_priv,"Device %pM claimed by another backbone gw. Don't send ARP reply!" , - dat_entry->mac_addr); + mac); ret = true; goto out; } skb_new =batadv_dat_arp_create_reply (bat_priv, ip_dst, ip_src, - dat_entry->mac_addr, - hw_src, vid); + mac, hw_src, vid);if (!skb_new) goto out;
@@ -1259,6 +1266,8 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,struct batadv_dat_entry *dat_entry =NULL ;bool ret = false;unsigned short vid; +u8 mac[ETH_ALEN ]; +u64 u64_mac;int err;if (!atomic_read (&bat_priv->distributed_arp_table))
@@ -1286,8 +1295,11 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,if (!dat_entry) goto out; + u64_mac =atomic64_read (&dat_entry->mac_addr); +u64_to_ether_addr (u64_mac, mac); + skb_new =batadv_dat_arp_create_reply (bat_priv, ip_dst, ip_src, - dat_entry->mac_addr, hw_src, vid); + mac, hw_src, vid);if (!skb_new) goto out;
@@ -1378,6 +1390,8 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,u8 *hw_src, *hw_dst;bool dropped = false;unsigned short vid; +u8 mac[ETH_ALEN ]; +u64 u64_mac;if (!atomic_read (&bat_priv->distributed_arp_table)) goto out;
@@ -1406,11 +1420,17 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,* this frame would lead to doubled receive of an ARP reply. */ dat_entry =batadv_dat_entry_hash_find (bat_priv, ip_src, vid); -if (dat_entry &&batadv_compare_eth (hw_src, dat_entry->mac_addr)) { -batadv_dbg (BATADV_DBG_DAT , bat_priv,"Doubled ARP reply removed: ARP MSG = [src: %pM-%pI4 dst: %pM-%pI4]; dat_entry: %pM-%pI4\n" , - hw_src, &ip_src, hw_dst, &ip_dst, - dat_entry->mac_addr, &dat_entry->ip); - dropped = true; +if (dat_entry) { + u64_mac =atomic64_read (&dat_entry->mac_addr); +u64_to_ether_addr (u64_mac, mac); + +if (batadv_compare_eth (hw_src, mac)) { +batadv_dbg (BATADV_DBG_DAT , bat_priv, +"Doubled ARP reply removed: ARP MSG = [src: %pM-%pI4 dst: %pM-%pI4]; dat_entry: %pM-%pI4\n" , + hw_src, &ip_src, hw_dst, &ip_dst, + mac, &dat_entry->ip); + dropped = true; + } }/* Update our internal cache with both the IP addresses the node got
net/batman-adv/types.h +1 -1
@@ -2365,7 +2365,7 @@ struct batadv_dat_entry {__be32 ip;/** @mac_addr: the MAC address associated to the stored IPv4 */ -u8 mac_addr[ETH_ALEN ]; +atomic64_t mac_addr;/** @vid: the vlan ID associated to this entry */ unsigned short vid;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 302/1376 batman-adv: bla: avoid CRC corruption due to parallel claim add
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 08645ab95768b88e2ff85a89211994651710465b upstream.
batadv_bla_add_claim() is used to add claims and modify the backbone of claims for CLAIM frames from remote backbones and local packets. When it handles a claim, it needs to either
* add the new claim's CRC to the backbone CRC
* remove the already existing claim's CRC from the old backbone and add it to the new backbone
But when the "new" claim code was running in parallel to the "change backbone" code, it can happen that the CRC was invalid because the backbone_gw of the claim was changed twice in the "new" claim code path:
* CPU0 creates the claim for gateway A and publishes it in the claim hash. The crc16 of the address has not yet been added to A's crc at this point.
* CPU1 processes a claim frame of gateway B for the same client, finds the just published claim, and performs the ownership change: it switches the pointer to B, removes the crc16 from A's crc - which never contained it - and adds it to B's crc.
* CPU0 continues behind the creation branch, unconditionally switches the pointer back to A without compensating B's crc (its remove_crc is false for the creation path), and finally adds the crc16 to A's crc
The CRC is then wrong for both:
* claim belongs to A: but CRC is not part of backbone A's CRC
* claim doesn't belong to B: CRC is still part of backbone B's CRC
This wrong CRC is never recomputated from the stored claims. For local backbone claims, this can also not recovered using syncs.
To avoid this, split the functionality in clear separate parts:
* new claim which always adds claim CRC to the backbone CRC (but never changes the already set backbone_gw of the claim back)
* update of existing claim which automatically changes the backbone_gw entry and only updates both backbone CRCs when there was an actual change
--- net/batman-adv/bridge_loop_avoidance.c | 63 ++++++++++++++++---------- 1 file changed, 39 insertions(+), 24 deletions(-)
net/batman-adv/bridge_loop_avoidance.c +39 -24
@@ -693,12 +693,14 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv,struct batadv_bla_backbone_gw *old_backbone_gw;struct batadv_bla_claim *claim;struct batadv_bla_claim search_claim; -bool remove_crc = false;int hash_added; +u16 claim_crc; +bool changed;ether_addr_copy (search_claim.addr, mac); search_claim.vid = vid; claim =batadv_claim_hash_find (bat_priv, &search_claim); + claim_crc =crc16 (0 , mac,ETH_ALEN );/* create a new claim entry if it does not exist yet. */ if (!claim) {
@@ -730,43 +732,56 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv,kfree (claim);return ; } + +spin_lock_bh (&backbone_gw->crc_lock); + backbone_gw->crc ^= claim_crc; +spin_unlock_bh (&backbone_gw->crc_lock); + +WRITE_ONCE (backbone_gw->lasttime, jiffies); + +batadv_claim_put (claim); +return ; + } + +WRITE_ONCE (claim->lasttime, jiffies); + +/* replace backbone_gw atomically and adjust reference counters */ +spin_lock_bh (&claim->backbone_lock); +if (claim->backbone_gw != backbone_gw) { + changed = true; + + old_backbone_gw = claim->backbone_gw; +kref_get (&backbone_gw->refcount); + claim->backbone_gw = backbone_gw; }else { -WRITE_ONCE (claim->lasttime, jiffies); -if (claim->backbone_gw == backbone_gw) -/* no need to register a new backbone */ - goto claim_free_ref; + old_backbone_gw =NULL ; + changed = false; + } +spin_unlock_bh (&claim->backbone_lock); +if (changed) {batadv_dbg (BATADV_DBG_BLA , bat_priv,"%s(): changing ownership for %pM, vid %d to gw %pM\n" , __func__, mac,batadv_print_vid (vid), backbone_gw->orig); - remove_crc = true; - } +/* add claim address to new backbone_gw */ +spin_lock_bh (&backbone_gw->crc_lock); + backbone_gw->crc ^= claim_crc; +spin_unlock_bh (&backbone_gw->crc_lock); -/* replace backbone_gw atomically and adjust reference counters */ -spin_lock_bh (&claim->backbone_lock); - old_backbone_gw = claim->backbone_gw; -kref_get (&backbone_gw->refcount); - claim->backbone_gw = backbone_gw; -spin_unlock_bh (&claim->backbone_lock); +WRITE_ONCE (backbone_gw->lasttime, jiffies); + } -if (remove_crc) { +if (old_backbone_gw) {/* remove claim address from old backbone_gw */ spin_lock_bh (&old_backbone_gw->crc_lock); - old_backbone_gw->crc ^=crc16 (0 , claim->addr,ETH_ALEN ); + old_backbone_gw->crc ^= claim_crc;spin_unlock_bh (&old_backbone_gw->crc_lock); - } - -batadv_backbone_gw_put (old_backbone_gw); -/* add claim address to new backbone_gw */ -spin_lock_bh (&backbone_gw->crc_lock); - backbone_gw->crc ^=crc16 (0 , claim->addr,ETH_ALEN ); -spin_unlock_bh (&backbone_gw->crc_lock); -WRITE_ONCE (backbone_gw->lasttime, jiffies); +batadv_backbone_gw_put (old_backbone_gw); + } -claim_free_ref:batadv_claim_put (claim); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 303/1376 perf sched: Fix register_pid() overflow, strcpy, and BUG_ON
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
commit 5949d339f5ec98752d56dcd4e36f619a59d513a5 upstream.
register_pid() has several issues when processing untrusted perf.data:
1. Integer overflow: (pid + 1) * sizeof(struct task_desc *) can wrap to a small value on 32-bit systems when pid is large (e.g. 0x40000000), causing realloc to return a tiny buffer followed by out-of-bounds writes in the initialization loop.
2. Heap buffer overflow: strcpy(task->comm, comm) copies the untrusted comm string into a fixed 20-byte COMM_LEN buffer with no length check.
3. BUG_ON on allocation failure: perf.data is untrusted input, so allocation failures should be handled gracefully rather than killing the process.
4. Realloc of sched->tasks assigned directly back, leaking the old pointer on failure; nr_tasks incremented before the realloc, leaving corrupted state on failure.
Cap pid at PID_MAX_LIMIT (4194304, matching the kernel's maximum on 64-bit), replace strcpy with strlcpy, guard against NULL comm, replace BUG_ON with NULL returns using safe realloc patterns, and add NULL checks in callers that dereference the result.
--- tools/perf/builtin-sched.c | 40 ++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-)
tools/perf/builtin-sched.c +30 -10
@@ -51,6 +51,7 @@#define COMM_LEN 20#define SYM_LEN 129#define MAX_PID 1024000 +#define PID_MAX_LIMIT 4194304/* kernel limit on 64-bit */ #define MAX_PRIO 140static const char *cpu_list;
@@ -440,17 +441,28 @@ static void add_sched_event_sleep(struct perf_sched *sched, struct task_desc *tastatic struct task_desc *register_pid (struct perf_sched *sched,unsigned long pid,const char *comm) { -struct task_desc *task; +struct task_desc *task, **tasks_p;static int pid_max; +/* perf.data is untrusted — cap pid to prevent overflow in size calculations */ +if (pid >=PID_MAX_LIMIT ) { +pr_err ("pid %lu exceeds limit %d, skipping\n" , pid,PID_MAX_LIMIT ); +return NULL ; + } +if (sched->pid_to_task ==NULL ) {if (sysctl__read_int ("kernel/pid_max" , &pid_max) <0 ) pid_max =MAX_PID ; -BUG_ON ((sched->pid_to_task =calloc (pid_max,sizeof (struct task_desc *))) ==NULL ); + sched->pid_to_task =calloc (pid_max,sizeof (struct task_desc *)); +if (sched->pid_to_task ==NULL ) +return NULL ; }if (pid >= (unsigned long )pid_max) { -BUG_ON ((sched->pid_to_task =realloc (sched->pid_to_task, (pid +1 ) * -sizeof (struct task_desc *))) ==NULL ); +void *p =realloc (sched->pid_to_task, (pid +1 ) *sizeof (struct task_desc *)); + +if (p ==NULL ) +return NULL ; + sched->pid_to_task = p;while (pid >= (unsigned long )pid_max) sched->pid_to_task[pid_max++] =NULL ; }
@@ -461,9 +473,11 @@ static struct task_desc *register_pid(struct perf_sched *sched,return task; task =zalloc (sizeof (*task)); +if (task ==NULL ) +return NULL ; task->pid = pid; - task->nr = sched->nr_tasks; -strcpy (task->comm, comm); +if (comm) +strlcpy (task->comm, comm,sizeof (task->comm));/* * every task starts in sleeping state - this gets ignored * if there's no wakeup pointing to this sleep state:
@@ -471,10 +485,12 @@ static struct task_desc *register_pid(struct perf_sched *sched,add_sched_event_sleep (sched, task,0 ,0 ); sched->pid_to_task[pid] = task; - sched->nr_tasks++; - sched->tasks =realloc (sched->tasks, sched->nr_tasks *sizeof (struct task_desc *)); -BUG_ON (!sched->tasks); - sched->tasks[task->nr] = task; + tasks_p =realloc (sched->tasks, (sched->nr_tasks +1 ) *sizeof (struct task_desc *)); +if (!tasks_p) +return NULL ; + sched->tasks = tasks_p; + sched->tasks[sched->nr_tasks] = task; + task->nr = sched->nr_tasks++;if (verbose >0 )printf ("registered task #%ld, PID %ld (%s)\n" , sched->nr_tasks, pid, comm);
@@ -838,6 +854,8 @@ replay_wakeup_event(struct perf_sched *sched, waker =register_pid (sched, sample->tid,"<unknown>" ); wakee =register_pid (sched, pid, comm); +if (waker ==NULL || wakee ==NULL ) +return -1 ;add_sched_event_wakeup (sched, waker, sample->time, wakee);return 0 ;
@@ -880,6 +898,8 @@ static int replay_switch_event(struct perf_sched *sched, prev =register_pid (sched, prev_pid, prev_comm); next =register_pid (sched, next_pid, next_comm); +if (prev ==NULL || next ==NULL ) +return -1 ; sched->cpu_last_switched[cpu] = timestamp;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 304/1376 clk: meson: align gxbb_32k_clk_sel number of parents with actual count
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Martin Blumenstingl <[email protected]>
[ Upstream commit 628b6fee9fca292f12d07f0f1bcf1edefa949d81 ]
The following out-of-bounds read has been observed by Christian on a GXBB WeTek Hub:
==================================================================
BUG: KASAN: global-out-of-bounds in __clk_register+0x1b70/0x2418
Read of size 8 at addr ffffd66320cf88e0 by task swapper/0/1
CPU: 0 UID: 0 PID: 1 Comm: swapper/0 Not tainted 7.0.0-rc5 #1 PREEMPT
Hardware name: WeTek Hub (DT)
Call trace:
show_stack+0x14/0x20 (C)
dump_stack_lvl+0x74/0x94
print_report+0x164/0x4b0
kasan_report+0x98/0xd8
__asan_report_load8_noabort+0x1c/0x24
__clk_register+0x1b70/0x2418
devm_clk_hw_register+0x74/0x15c
meson_clkc_init+0xd4/0x20c
meson_clkc_syscon_probe+0x5c/0x94
platform_probe+0xbc/0x17c
really_probe+0x184/0x844
__driver_probe_device+0x154/0x35c
driver_probe_device+0x60/0x188
__driver_attach+0x168/0x4a0
bus_for_each_dev+0xec/0x180
driver_attach+0x38/0x58
bus_add_driver+0x238/0x4c0
driver_register+0x150/0x388
__platform_driver_register+0x54/0x7c
gxbb_clkc_driver_init+0x18/0x20
do_one_initcall+0xb8/0x340
kernel_init_freeable+0x49c/0x52c
kernel_init+0x24/0x148
ret_from_fork+0x10/0x20
The buggy address belongs to the variable:
gxbb_32k_clk_parents+0x60/0x400
The buggy address belongs to a vmalloc virtual mapping
The buggy address belongs to the physical page:
Memory state around the buggy address:
ffffd66320cf8780: 00 00 00 00 f9 f9 f9 f9 00 f9 f9 f9 f9 f9 f9 f9
ffffd66320cf8800: 00 04 f9 f9 f9 f9 f9 f9 00 04 f9 f9 f9 f9 f9 f9
>ffffd66320cf8880: 00 00 00 00 00 00 00 00 00 00 00 00 f9 f9 f9 f9
^
ffffd66320cf8900: 00 01 f9 f9 f9 f9 f9 f9 00 06 f9 f9 f9 f9 f9 f9
ffffd66320cf8980: 00 00 02 f9 f9 f9 f9 f9 00 00 02 f9 f9 f9 f9 f9
==================================================================Commit 7915d7d5407c ("clk: amlogic: gxbb: drop non existing 32k clock parent") dropped a non-existing clock parent from the gxbb_32k_clk_sel mux but didn't adjust the hard-coded num_parents field. Fix the actual number of parents of that mux by using ARRAY_SIZE instead (avoiding similar problems in future).
--- drivers/clk/meson/gxbb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/meson/gxbb.c +1 -1
@@ -1305,7 +1305,7 @@ static struct clk_regmap gxbb_32k_clk_sel = { .name = "32k_clk_sel", .ops = &clk_regmap_mux_ops, .parent_data = gxbb_32k_clk_parent_data, - .num_parents = 4, + .num_parents = ARRAY_SIZE(gxbb_32k_clk_parent_data), .flags = CLK_SET_RATE_PARENT, }, };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 305/1376 batman-adv: fix TX priority extraction for BATADV_FORW_MCAST
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 7aedb59b80993c912ab45ce24386a2775150962b upstream.
batadv_mcast_forw_mode_by_count() pushs the skb->data for BATADV_FORW_MCAST forwarding via batadv_mcast_forw_mcsend(). But the batadv_skb_set_priority() expects the ethernet header directly before (skb->data + offset). With the moved skb->data, just some random data would be accessed to get the priority data.
Move the batadv_skb_set_priority() before the decision about the handling multicast packets and potential header modifications.
--- net/batman-adv/soft-interface.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
net/batman-adv/soft-interface.c +5 -2
@@ -271,6 +271,8 @@ static netdev_tx_t batadv_interface_tx(struct sk_buff *skb,if (batadv_compare_eth (ethhdr->h_dest, ectp_addr)) goto dropped; +batadv_skb_set_priority (skb,0 ); + gw_mode =atomic_read (&bat_priv->gw.mode);if (is_multicast_ether_addr (ethhdr->h_dest)) {/* if gw mode is off, broadcast every packet */
@@ -304,6 +306,9 @@ static netdev_tx_t batadv_interface_tx(struct sk_buff *skb, send:if (do_bcast && !is_broadcast_ether_addr (ethhdr->h_dest)) { +/* WARNING batadv_mcast_forw_mode might add more headers +* in front of the skb. and might even reallocate the skb +*/ forw_mode =batadv_mcast_forw_mode (bat_priv, skb, vid, &mcast_is_routable);switch (forw_mode) {
@@ -321,8 +326,6 @@ static netdev_tx_t batadv_interface_tx(struct sk_buff *skb, } } -batadv_skb_set_priority (skb,0 ); -/* ethernet packet should be broadcasted */ if (do_bcast) { primary_if =batadv_primary_if_get_selected (bat_priv);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 306/1376 mm/damon/core: skip aging from repeated aggressive merging
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: SJ Park <[email protected]>
[ Upstream commit 0250dbe08c730d003ef9f484da56ae09a1ea0c4c ]
The number of DAMON regions could temporarily exceed the user-defined maximum number of regions limit for corner cases. For example, users could lower the limit via runtime parameters update. For such a case, kdamond_merge_regions() repeats merging regions in the case doubling the merge threshold. The repeated merge operation could update the age of regions multiple times. This corrupts the monitoring results. Fix the issue by asking the merge operation to skip aging for the corner case.
The user impact is degradation of the monitoring quality. The impact should be mild, since the degradation is only temporal, and it is not common to happen in realistic setups.
The issue was discovered [1,2] by Sashiko.
--- mm/damon/core.c | 17 +++++++++++------ mm/damon/tests/core-kunit.h | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-)
mm/damon/core.c +11 -6
@@ -1786,15 +1786,17 @@ static void damon_merge_two_regions(struct damon_target *t,* sz_limit size upper limit of each region */ static void damon_merge_regions_of (struct damon_target *t,unsigned int thres, -unsigned long sz_limit) +unsigned long sz_limit,bool count_age) {struct damon_region *r, *prev =NULL , *next;damon_for_each_region_safe (r, next, t) { -if (abs (r->nr_accesses - r->last_nr_accesses) > thres) - r->age =0 ; -else - r->age++; +if (count_age) { +if (abs (r->nr_accesses - r->last_nr_accesses) > thres) + r->age =0 ; +else + r->age++; + } if (prev && prev->ar.end == r->ar.start && abs(prev->nr_accesses - r->nr_accesses) <= thres &&
@@ -1828,15 +1830,18 @@ static void kdamond_merge_regions(struct damon_ctx *c, unsigned int threshold,struct damon_target *t;unsigned int nr_regions;unsigned int max_thres; +bool count_age = true; max_thres = c->attrs.aggr_interval / (c->attrs.sample_interval ? c->attrs.sample_interval :1 );do { nr_regions =0 ;damon_for_each_target (t, c) { -damon_merge_regions_of (t, threshold, sz_limit); +damon_merge_regions_of (t, threshold, sz_limit, + count_age); nr_regions +=damon_nr_regions (t); } + count_age = false; threshold =max (1 , threshold *2 ); }while (nr_regions > c->attrs.max_nr_regions && threshold /2 < max_thres);
mm/damon/tests/core-kunit.h +1 -1
@@ -266,7 +266,7 @@ static void damon_test_merge_regions_of(struct kunit *test)damon_add_region (r, t); } -damon_merge_regions_of (t,9 ,9999 ); +damon_merge_regions_of (t,9 ,9999 , true);/* 0-112, 114-130, 130-156, 156-170 */ KUNIT_EXPECT_EQ (test,damon_nr_regions (t),5u );if (damon_nr_regions (t) !=5 )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 307/1376 Smack: Fix error in capability bypass
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Casey Schaufler <[email protected]>
[ Upstream commit b2faddc13112489f8f11eb40b9456db8c1b58362 ]
A bug in smack_inode_xattr_skipcap() was introduced in the inode capability handling. The strncmp guard at the top of the function is coded backwards, resulting in consistently incorrect results. Correct the check, and the code functions as it should. The error manifests as requiring CAP_SYS_ADMIN as well as CAP_MAC_ADMIN to change an inode's MAC attributes.
--- security/smack/smack_lsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
security/smack/smack_lsm.c +1 -1
@@ -1329,7 +1329,7 @@ static int smack_inode_getattr(const struct path *path)*/ static int smack_inode_xattr_skipcap (const char *name) { -if (strncmp (name,XATTR_SMACK_SUFFIX ,strlen (XATTR_SMACK_SUFFIX ))) +if (strncmp (name,XATTR_SMACK_SUFFIX ,strlen (XATTR_SMACK_SUFFIX )) ==0 )return 0 ; if (strcmp(name, XATTR_NAME_SMACK) == 0 ||
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 308/1376 drm: Remove unused header in drm_dumb_buffers.c
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yicong Hui <[email protected]>
[ Upstream commit 38b4ce17ef3421fb0e5e6dbdab1974282bde1165 ]
Remove the header #include "drm_internal.h" from drm_dumb_buffers.c, which is included but not used.
Header was introduced in commit 47f10854ca89 ("drm: Don't export the drm_gem_dumb_destroy() function") when moving functions, but was not removed in commit 96a7b60f6ddb ("drm: remove dumb_destroy callback") when the drm_gem_dumb_destroy function was removed.
Compiles successfully with DRM enabled, pass kunit tests and IGT-tests in a vng virtual machine.
--- drivers/gpu/drm/drm_dumb_buffers.c | 1 - 1 file changed, 1 deletion(-)
drivers/gpu/drm/drm_dumb_buffers.c +0 -1
@@ -29,7 +29,6 @@#include <drm/drm_mode.h> #include "drm_crtc_internal.h" -#include "drm_internal.h" /** * DOC: overview
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 309/1376 drm: lcdif: Wait for vblank before disabling DMA
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Kocialkowski <[email protected]>
[ Upstream commit 351af554edd994898db12217c3be39979e168d35 ]
It is necessary to wait for the full frame to finish streaming through the DMA engine before we can safely disable it by removing the DISP_PARA_DISP_ON bit. Disabling it in-flight can leave the hardware confused and unable to resume streaming for the next frame.
This causes the FIFO underrun and empty status bits to be set and a single solid color to be shown on the display, coming from one of the pixels of the previous frame. The issue occurs sporadically when a new mode is set, which triggers the crtc disable and enable paths.
Setting the shadow load bit and waiting for it to be cleared by the DMA engine allows waiting for completion.
The NXP BSP driver addresses this issue with a hardcoded 25 ms sleep.
--- drivers/gpu/drm/mxsfb/lcdif_kms.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)
drivers/gpu/drm/mxsfb/lcdif_kms.c +12 -3
@@ -373,14 +373,23 @@ static void lcdif_disable_controller(struct lcdif_drm_private *lcdif)int ret; reg =readl (lcdif->base +LCDC_V8_CTRLDESCL0_5 ); +/* Disable the layer for DMA. */ reg &= ~CTRLDESCL0_5_EN ; +/* +* It is necessary to wait for the full frame to finish streaming +* through the DMA engine before we can safely disable it by removing +* the DISP_PARA_DISP_ON bit. Disabling it in-flight can leave the +* hardware confused and unable to resume streaming for the next frame. +*/ + reg |=CTRLDESCL0_5_SHADOW_LOAD_EN ;writel (reg, lcdif->base +LCDC_V8_CTRLDESCL0_5 ); +/* Wait for the frame to finish or timeout after 50 ms. */ ret =readl_poll_timeout (lcdif->base +LCDC_V8_CTRLDESCL0_5 , - reg, !(reg &CTRLDESCL0_5_EN ), -0 ,36000 );/* Wait ~2 frame times max */ + reg, !(reg &CTRLDESCL0_5_SHADOW_LOAD_EN ), +200 ,50000 );if (ret) -drm_err (lcdif->drm,"Failed to disable controller!\n" ); +drm_err (lcdif->drm,"Timed out waiting for final vblank!\n" ); reg =readl (lcdif->base +LCDC_V8_DISP_PARA ); reg &= ~DISP_PARA_DISP_ON ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 310/1376 drm/v3d: Replace a global spinlock with a per-queue spinlock
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maíra Canal <[email protected]>
[ Upstream commit e9d8e027483267a9505f5b6b7f0476b5299743af ]
Each V3D queue works independently and all the dependencies between the jobs are handled through the DRM scheduler. Therefore, there is no need to use one single lock for all queues. Using it, creates unnecessary contention between different queues that can operate independently.
Replace the global spinlock with per-queue locks to improve parallelism and reduce contention between different V3D queues (BIN, RENDER, TFU, CSD). This allows independent queues to operate concurrently while maintaining proper synchronization within each queue.
Stable-dep-of: 25a166990751 ("drm/v3d: Clear queue->active_job when v3d_fence_create() fails")
--- drivers/gpu/drm/v3d/v3d_drv.h | 8 ++------ drivers/gpu/drm/v3d/v3d_fence.c | 11 ++++++----- drivers/gpu/drm/v3d/v3d_gem.c | 3 ++- drivers/gpu/drm/v3d/v3d_irq.c | 6 +++--- drivers/gpu/drm/v3d/v3d_sched.c | 13 +++++++------ 5 files changed, 20 insertions(+), 21 deletions(-)
drivers/gpu/drm/v3d/v3d_drv.h +2 -6
@@ -62,6 +62,7 @@ struct v3d_queue_state {/* Currently active job for this queue */ struct v3d_job *active_job; +spinlock_t queue_lock; };/* Performance monitor object. The perform lifetime is controlled by userspace
@@ -154,11 +155,6 @@ struct v3d_dev {struct v3d_queue_state queue[V3D_MAX_QUEUES ]; -/* Spinlock used to synchronize the overflow memory -* management against bin job submission. -*/ -spinlock_t job_lock; -/* Used to track the active perfmon if any. */ struct v3d_perfmon *active_perfmon;
@@ -532,7 +528,7 @@ void v3d_get_stats(const struct v3d_stats *stats, u64 timestamp,/* v3d_fence.c */ extern const struct dma_fence_ops v3d_fence_ops; -struct dma_fence *v3d_fence_create (struct v3d_dev *v3d,enum v3d_queue queue); +struct dma_fence *v3d_fence_create (struct v3d_dev *v3d,enum v3d_queue q);/* v3d_gem.c */ int v3d_gem_init (struct drm_device *dev);
drivers/gpu/drm/v3d/v3d_fence.c +6 -5
@@ -3,8 +3,9 @@#include "v3d_drv.h" -struct dma_fence *v3d_fence_create (struct v3d_dev *v3d,enum v3d_queue queue) +struct dma_fence *v3d_fence_create (struct v3d_dev *v3d,enum v3d_queue q) { +struct v3d_queue_state *queue = &v3d->queue[q];struct v3d_fence *fence; fence =kzalloc (sizeof (*fence),GFP_KERNEL );
@@ -12,10 +13,10 @@ struct dma_fence *v3d_fence_create(struct v3d_dev *v3d, enum v3d_queue queue)return ERR_PTR (-ENOMEM ); fence->dev = &v3d->drm; - fence->queue = queue; - fence->seqno = ++v3d->queue[queue].emit_seqno; -dma_fence_init (&fence->base, &v3d_fence_ops, &v3d->job_lock, - v3d->queue[queue].fence_context, fence->seqno); + fence->queue = q; + fence->seqno = ++queue->emit_seqno; +dma_fence_init (&fence->base, &v3d_fence_ops, &queue->queue_lock, + queue->fence_context, fence->seqno);return &fence->base; }
drivers/gpu/drm/v3d/v3d_gem.c +2 -1
@@ -254,10 +254,11 @@ v3d_gem_init(struct drm_device *dev) queue->fence_context =dma_fence_context_alloc (1 );memset (&queue->stats,0 ,sizeof (queue->stats));seqcount_init (&queue->stats.lock); + +spin_lock_init (&queue->queue_lock); }spin_lock_init (&v3d->mm_lock); -spin_lock_init (&v3d->job_lock); ret =drmm_mutex_init (dev, &v3d->bo_lock);if (ret)return ret;
drivers/gpu/drm/v3d/v3d_irq.c +3 -3
@@ -62,17 +62,17 @@ v3d_overflow_mem_work(struct work_struct *work)* bin job got scheduled, that's fine. We'll just give them * some binner pool anyway. */ -spin_lock_irqsave (&v3d->job_lock, irqflags); +spin_lock_irqsave (&queue->queue_lock, irqflags); bin_job = (struct v3d_bin_job *)queue->active_job;if (!bin_job) { -spin_unlock_irqrestore (&v3d->job_lock, irqflags); +spin_unlock_irqrestore (&queue->queue_lock, irqflags); goto out; }drm_gem_object_get (obj);list_add_tail (&bo->unref_head, &bin_job->render->unref_list); -spin_unlock_irqrestore (&v3d->job_lock, irqflags); +spin_unlock_irqrestore (&queue->queue_lock, irqflags);v3d_mmu_flush_all (v3d);
drivers/gpu/drm/v3d/v3d_sched.c +7 -6
@@ -204,27 +204,28 @@ static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job) {struct v3d_bin_job *job =to_bin_job (sched_job);struct v3d_dev *v3d = job->base.v3d; +struct v3d_queue_state *queue = &v3d->queue[V3D_BIN ];struct drm_device *dev = &v3d->drm;struct dma_fence *fence;unsigned long irqflags;if (unlikely (job->base.base.s_fence->finished.error)) { -spin_lock_irqsave (&v3d->job_lock, irqflags); - v3d->queue[V3D_BIN ].active_job =NULL ; -spin_unlock_irqrestore (&v3d->job_lock, irqflags); +spin_lock_irqsave (&queue->queue_lock, irqflags); + queue->active_job =NULL ; +spin_unlock_irqrestore (&queue->queue_lock, irqflags);return NULL ; }/* Lock required around bin_job update vs * v3d_overflow_mem_work(). */ -spin_lock_irqsave (&v3d->job_lock, irqflags); - v3d->queue[V3D_BIN ].active_job = &job->base; +spin_lock_irqsave (&queue->queue_lock, irqflags); + queue->active_job = &job->base;/* Clear out the overflow allocation, so we don't * reuse the overflow attached to a previous job. */ V3D_CORE_WRITE (0 ,V3D_PTB_BPOS ,0 ); -spin_unlock_irqrestore (&v3d->job_lock, irqflags); +spin_unlock_irqrestore (&queue->queue_lock, irqflags);v3d_invalidate_caches (v3d);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 311/1376 drm/v3d: Clear queue->active_job when v3d_fence_create() fails
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maíra Canal <[email protected]>
[ Upstream commit 25a1669907512e927fab9ad4d4fb74ff57f63cd9 ]
The run_job() callbacks for BIN, RENDER, TFU and CSD assign the incoming job to queue->active_job before calling v3d_fence_create(). If v3d_fence_create() fails, the callback returns NULL without clearing active_job, leaving a dangling pointer.
Create a failure path in all run_job() callbacks that clears the active job before returning NULL. The BIN path takes queue->queue_lock around the clear as it races against v3d_overflow_mem_work(); RENDER, TFU and CSD paths have no concurrent reader, so the clear is lock-free.
--- drivers/gpu/drm/v3d/v3d_sched.c | 60 +++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 26 deletions(-)
drivers/gpu/drm/v3d/v3d_sched.c +34 -26
@@ -206,15 +206,11 @@ static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job)struct v3d_dev *v3d = job->base.v3d;struct v3d_queue_state *queue = &v3d->queue[V3D_BIN ];struct drm_device *dev = &v3d->drm; -struct dma_fence *fence; +struct dma_fence *fence =NULL ;unsigned long irqflags; -if (unlikely (job->base.base.s_fence->finished.error)) { -spin_lock_irqsave (&queue->queue_lock, irqflags); - queue->active_job =NULL ; -spin_unlock_irqrestore (&queue->queue_lock, irqflags); -return NULL ; - } +if (unlikely (job->base.base.s_fence->finished.error)) + goto out_clean_job;/* Lock required around bin_job update vs * v3d_overflow_mem_work().
@@ -231,7 +227,7 @@ static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job) fence =v3d_fence_create (v3d,V3D_BIN );if (IS_ERR (fence)) -return NULL ; + goto out_clean_job;if (job->base.irq_fence)dma_fence_put (job->base.irq_fence);
@@ -259,6 +255,12 @@ static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job)V3D_CORE_WRITE (0 ,V3D_CLE_CT0QEA , job->end);return fence; + +out_clean_job: +spin_lock_irqsave (&queue->queue_lock, irqflags); + queue->active_job =NULL ; +spin_unlock_irqrestore (&queue->queue_lock, irqflags); +return fence; }static struct dma_fence *v3d_render_job_run (struct drm_sched_job *sched_job)
@@ -266,12 +268,10 @@ static struct dma_fence *v3d_render_job_run(struct drm_sched_job *sched_job)struct v3d_render_job *job =to_render_job (sched_job);struct v3d_dev *v3d = job->base.v3d;struct drm_device *dev = &v3d->drm; -struct dma_fence *fence; +struct dma_fence *fence =NULL ; -if (unlikely (job->base.base.s_fence->finished.error)) { - v3d->queue[V3D_RENDER ].active_job =NULL ; -return NULL ; - } +if (unlikely (job->base.base.s_fence->finished.error)) + goto out_clean_job; v3d->queue[V3D_RENDER ].active_job = &job->base;
@@ -285,7 +285,7 @@ static struct dma_fence *v3d_render_job_run(struct drm_sched_job *sched_job) fence =v3d_fence_create (v3d,V3D_RENDER );if (IS_ERR (fence)) -return NULL ; + goto out_clean_job;if (job->base.irq_fence)dma_fence_put (job->base.irq_fence);
@@ -306,6 +306,10 @@ static struct dma_fence *v3d_render_job_run(struct drm_sched_job *sched_job)V3D_CORE_WRITE (0 ,V3D_CLE_CT1QEA , job->end);return fence; + +out_clean_job: + v3d->queue[V3D_RENDER ].active_job =NULL ; +return fence; } static struct dma_fence *
@@ -314,18 +318,16 @@ v3d_tfu_job_run(struct drm_sched_job *sched_job)struct v3d_tfu_job *job =to_tfu_job (sched_job);struct v3d_dev *v3d = job->base.v3d;struct drm_device *dev = &v3d->drm; -struct dma_fence *fence; +struct dma_fence *fence =NULL ; -if (unlikely (job->base.base.s_fence->finished.error)) { - v3d->queue[V3D_TFU ].active_job =NULL ; -return NULL ; - } +if (unlikely (job->base.base.s_fence->finished.error)) + goto out_clean_job; v3d->queue[V3D_TFU ].active_job = &job->base; fence =v3d_fence_create (v3d,V3D_TFU );if (IS_ERR (fence)) -return NULL ; + goto out_clean_job;if (job->base.irq_fence)dma_fence_put (job->base.irq_fence);
@@ -353,6 +355,10 @@ v3d_tfu_job_run(struct drm_sched_job *sched_job)V3D_WRITE (V3D_TFU_ICFG (v3d->ver), job->args.icfg |V3D_TFU_ICFG_IOC );return fence; + +out_clean_job: + v3d->queue[V3D_TFU ].active_job =NULL ; +return fence; } static struct dma_fence *
@@ -361,13 +367,11 @@ v3d_csd_job_run(struct drm_sched_job *sched_job)struct v3d_csd_job *job =to_csd_job (sched_job);struct v3d_dev *v3d = job->base.v3d;struct drm_device *dev = &v3d->drm; -struct dma_fence *fence; +struct dma_fence *fence =NULL ;int i, csd_cfg0_reg; -if (unlikely (job->base.base.s_fence->finished.error)) { - v3d->queue[V3D_CSD ].active_job =NULL ; -return NULL ; - } +if (unlikely (job->base.base.s_fence->finished.error)) + goto out_clean_job;/* The HW interprets a workgroup size of 0 as 65536; however, the * user-space driver exposes a maximum of 65535. Therefore, a 0 in
@@ -385,7 +389,7 @@ v3d_csd_job_run(struct drm_sched_job *sched_job) fence =v3d_fence_create (v3d,V3D_CSD );if (IS_ERR (fence)) -return NULL ; + goto out_clean_job;if (job->base.irq_fence)dma_fence_put (job->base.irq_fence);
@@ -412,6 +416,10 @@ v3d_csd_job_run(struct drm_sched_job *sched_job)V3D_CORE_WRITE (0 , csd_cfg0_reg, job->args.cfg[0 ]);return fence; + +out_clean_job: + v3d->queue[V3D_CSD ].active_job =NULL ; +return fence; } static void
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 312/1376 drm/rockchip: vop2: Recognise 10-bit YUV422 as YUV format
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolas Frattaroli <[email protected]>
[ Upstream commit c1bfe8dac0a79d47eed313b9bcaa2658898684ec ]
The Rockchip VOP2 video output driver has a "is_yuv_output" function, which returns true when a given bus format is a YUV format, and false otherwise.
This switch statement is lacking the bus format used for YUV422 10-bit.
Add the two component orderings of the YUV422 10-bit bus formats to the switch statement.
--- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +2 -0
@@ -514,6 +514,8 @@ static bool is_yuv_output(u32 bus_format)switch (bus_format) {case MEDIA_BUS_FMT_YUV8_1X24 :case MEDIA_BUS_FMT_YUV10_1X30 : +case MEDIA_BUS_FMT_YUYV10_1X20 : +case MEDIA_BUS_FMT_UYVY10_1X20 :case MEDIA_BUS_FMT_UYYVYY8_0_5X24 :case MEDIA_BUS_FMT_UYYVYY10_0_5X30 :case MEDIA_BUS_FMT_YUYV8_2X8 :
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 313/1376 drm/bridge: cdns-mhdp8546: Return an error pointer on allocation failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maxime Ripard <[email protected]>
[ Upstream commit 30ac1d403438a6c6039f0af5bb2df3d021f96036 ]
The drm_bridge_funcs.atomic_reset documentation states that the hook must return either a valid drm_bridge_state object or an ERR_PTR().
The cdns_mhdp_bridge_atomic_reset() callback returns NULL when the allocation of its state fails, violating this contract.
Return ERR_PTR(-ENOMEM) instead.
--- drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +1 -1
@@ -2158,7 +2158,7 @@ cdns_mhdp_bridge_atomic_reset(struct drm_bridge *bridge) cdns_mhdp_state =kzalloc (sizeof (*cdns_mhdp_state),GFP_KERNEL );if (!cdns_mhdp_state) -return NULL ; +return ERR_PTR (-ENOMEM );__drm_atomic_helper_bridge_reset (bridge, &cdns_mhdp_state->base);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 314/1376 smack: fix incorrect task context in smack_msg_queue_msgrcv
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Konstantin Andreev <[email protected]>
[ Upstream commit fba3d32825f4bbc8e20f0cdc3b14df57965b8fe5 ]
The smack_msg_queue_msgrcv() function incorrectly checks the permissions of the 'current' task instead of the 'target' task.
In the msgsnd() syscall path, if a receiver is already waiting, the pipelined_send() optimization is used to push the message directly to the receiver task:
ipc/msg.c`pipelined_send():
` smp_store_release(&msr->r_msg, msg)In this case, the 'sender' (current) task performs the check on behalf of the 'receiver' task (msr->r_tsk, passed as the 'target' parameter):
ipc/msg.c`pipelined_send():
` security_msg_queue_msgrcv(,, target := msr->r_tsk,,)
However, smack_msg_queue_msgrcv() ignores the 'target' and checks 'current':
smack_msg_queue_msgrcv(…)
` smk_curacc_msq(isp, MAY_READWRITE); // current task
'current' MAY satisfy smack_msg_queue_msgrcv r/w requirement, but 'target' (the receiver task) might NOT;
as a result, an unauthorized receiver gets the message, violating MAC policy.
Test:
1) create a sysv message queue with label “foo”
2) echo "bar foo r" >/smack/load2
3) msgrcv(,,,0,MSG_NOERROR) in "bar"-labeled task. The task is waiting for the messages ...
4) msgsnd() from a "foo"-labeled task:
"bar"-labeled task gets the message.
This patch fixes the issue by checking permission on the 'target' task instead of 'current'.
(2008-02-04, Casey Schaufler)
--- security/smack/smack_lsm.c | 65 +++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 18 deletions(-)
security/smack/smack_lsm.c +47 -18
@@ -147,12 +147,13 @@ static int smk_bu_note(char *note, struct smack_known *sskp,#define smk_bu_note (note, sskp, oskp, mode,RC ) (RC)#endif -#ifdef CONFIG_SECURITY_SMACK_BRINGUP -static int smk_bu_current (char *note,struct smack_known *oskp, -int mode,int rc) +static int +smk_bu_tsk_to_obj (struct task_struct *tsk,const struct task_smack *tsp, +char *note,struct smack_known *oskp,int mode,int rc) { -struct task_smack *tsp =smack_cred (current_cred ()); +#ifdef CONFIG_SECURITY_SMACK_BRINGUP char acc[SMK_NUM_ACCESS_TYPE +1 ]; +char comm[TASK_COMM_LEN ];if (rc <=0 )return rc;
@@ -160,14 +161,22 @@ static int smk_bu_current(char *note, struct smack_known *oskp, rc =0 ;smk_bu_mode (mode, acc); +pr_info ("Smack %s: (%s %s %s) %s %s\n" , smk_bu_mess[rc], - tsp->smk_task->smk_known, oskp->smk_known, - acc, current->comm, note); +smk_of_task (tsp)->smk_known, oskp->smk_known, + acc,get_task_comm (comm, tsk), note);return 0 ; -}#else -#define smk_bu_current (note, oskp, mode,RC ) (RC) +return rc;#endif +} + +static int smk_bu_current (char *note,struct smack_known *oskp, +int mode,int rc) +{ +return smk_bu_tsk_to_obj (current,smack_cred (current_cred ()), + note, oskp, mode, rc); +}#ifdef CONFIG_SECURITY_SMACK_BRINGUP static int smk_bu_task (struct task_struct *otp,int mode,int rc)
@@ -3360,14 +3369,20 @@ static int smack_sem_semop(struct kern_ipc_perm *isp, struct sembuf *sops, }/** -* smk_curacc_msq : helper to check if current has access on msq -* @isp : the msq +* smk_tskacc_msq : helper to check if tsk has access on msq +* @tsk: the task that requests access +* @isp : the sysv msg queue permissions * @access : access requested * -* return 0 if current has access, error otherwise +* return 0 if tsk has access, error otherwise */ -static int smk_curacc_msq (struct kern_ipc_perm *isp,int access) +static int +smk_tskacc_msq (struct task_struct *tsk,struct kern_ipc_perm *isp,int access) { +const bool tsk_is_current = (tsk == current); +const struct cred *const tsk_cred = + (tsk_is_current ?current_cred () :get_task_cred (tsk)); +struct task_smack *const tsp =smack_cred (tsk_cred);struct smack_known *msp =smack_of_ipc (isp);struct smk_audit_info ad;int rc;
@@ -3376,11 +3391,25 @@ static int smk_curacc_msq(struct kern_ipc_perm *isp, int access)smk_ad_init (&ad, __func__,LSM_AUDIT_DATA_IPC ); ad.a.u.ipc_id = isp->id;#endif - rc =smk_curacc (msp, access, &ad); - rc =smk_bu_current ("msq" , msp, access, rc); + rc =smk_tskacc (tsp, msp, access, &ad); + rc =smk_bu_tsk_to_obj (tsk, tsp,"msq" , msp, access, rc); +if (!tsk_is_current) +put_cred (tsk_cred);return rc; } +/** +* smk_curacc_msq : helper to check if current has access on msq +* @isp : the sysv msg queue permissions +* @access : access requested +* +* return 0 if current has access, error otherwise +*/ +static int smk_curacc_msq (struct kern_ipc_perm *isp,int access) +{ +return smk_tskacc_msq (current, isp, access); +} +/** * smack_msg_queue_associate - Smack access check for msg_queue * @isp: the object
@@ -3448,21 +3477,21 @@ static int smack_msg_queue_msgsnd(struct kern_ipc_perm *isp, struct msg_msg *msg }/** -* smack_msg_queue_msgrcv - Smack access check for msg_queue +* smack_msg_queue_msgrcv - check it target has r/w access to msg_queue * @isp: the object * @msg: unused -* @target: unused +* @target: the task that msgrcv() from the queue * @type: unused * @mode: unused * -* Returns 0 if current has read and write access, error code otherwise +* Returns 0 if target has read and write access, error code otherwise */ static int smack_msg_queue_msgrcv (struct kern_ipc_perm *isp,struct msg_msg *msg,struct task_struct *target,long type,int mode) { -return smk_curacc_msq (isp,MAY_READWRITE ); +return smk_tskacc_msq (target, isp,MAY_READWRITE ); }/**
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 315/1376 smack: simplify write handlers of sysfs entries
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Antipov <[email protected]>
[ Upstream commit b78fede1c69a090d377bf80417ce1f7f7f314534 ]
Use the convenient 'kstrto{u,s}32_from_user()' to simplify write handlers of /smack/{doi,direct,mapped,logging,ptrace} sysfs entries.
Stable-dep-of: 577dc3b6a8cf ("smack: deduplicate smackfs/{direct,mapped} file_operations")
--- security/smack/smackfs.c | 81 +++++++++++----------------------------- 1 file changed, 22 insertions(+), 59 deletions(-)
security/smack/smackfs.c +22 -59
@@ -1616,24 +1616,17 @@ static ssize_t smk_read_doi(struct file *filp, char __user *buf,static ssize_t smk_write_doi (struct file *file,const char __user *buf,size_t count,loff_t *ppos) { -char temp[80 ]; -unsigned long u; +int ret; +u32 u;if (!smack_privileged (CAP_MAC_ADMIN ))return -EPERM ; -if (count >=sizeof (temp) || count ==0 ) -return -EINVAL ; - -if (copy_from_user (temp, buf, count) !=0 ) -return -EFAULT ; - - temp[count] ='\0' ; + ret =kstrtou32_from_user (buf, count,10 , &u); +if (unlikely (ret)) +return ret; -if (kstrtoul (temp,10 , &u)) -return -EINVAL ; - -if (u ==CIPSO_V4_DOI_UNKNOWN || u >U32_MAX ) +if (u ==CIPSO_V4_DOI_UNKNOWN )return -EINVAL ;return smk_cipso_doi (u,GFP_KERNEL ) ? : count;
@@ -1682,22 +1675,14 @@ static ssize_t smk_write_direct(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct smack_known *skp; -char temp[80 ]; -int i; +int i, ret;if (!smack_privileged (CAP_MAC_ADMIN ))return -EPERM ; -if (count >=sizeof (temp) || count ==0 ) -return -EINVAL ; - -if (copy_from_user (temp, buf, count) !=0 ) -return -EFAULT ; - - temp[count] ='\0' ; - -if (sscanf (temp,"%d" , &i) !=1 ) -return -EINVAL ; + ret =kstrtos32_from_user (buf, count,10 , &i); +if (unlikely (ret)) +return ret;/* * Don't do anything if the value hasn't actually changed.
@@ -1760,22 +1745,14 @@ static ssize_t smk_write_mapped(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct smack_known *skp; -char temp[80 ]; -int i; +int i, ret;if (!smack_privileged (CAP_MAC_ADMIN ))return -EPERM ; -if (count >=sizeof (temp) || count ==0 ) -return -EINVAL ; - -if (copy_from_user (temp, buf, count) !=0 ) -return -EFAULT ; - - temp[count] ='\0' ; - -if (sscanf (temp,"%d" , &i) !=1 ) -return -EINVAL ; + ret =kstrtos32_from_user (buf, count,10 , &i); +if (unlikely (ret)) +return ret;/* * Don't do anything if the value hasn't actually changed.
@@ -2196,22 +2173,15 @@ static ssize_t smk_read_logging(struct file *filp, char __user *buf,static ssize_t smk_write_logging (struct file *file,const char __user *buf,size_t count,loff_t *ppos) { -char temp[32 ]; -int i; +int i, ret;if (!smack_privileged (CAP_MAC_ADMIN ))return -EPERM ; -if (count >=sizeof (temp) || count ==0 ) -return -EINVAL ; - -if (copy_from_user (temp, buf, count) !=0 ) -return -EFAULT ; + ret =kstrtos32_from_user (buf, count,10 , &i); +if (unlikely (ret)) +return ret; - temp[count] ='\0' ; - -if (sscanf (temp,"%d" , &i) !=1 ) -return -EINVAL ;if (i <0 || i >3 )return -EINVAL ; log_policy = i;
@@ -2854,22 +2824,15 @@ static ssize_t smk_read_ptrace(struct file *filp, char __user *buf,static ssize_t smk_write_ptrace (struct file *file,const char __user *buf,size_t count,loff_t *ppos) { -char temp[32 ]; -int i; +int i, ret;if (!smack_privileged (CAP_MAC_ADMIN ))return -EPERM ; -if (*ppos !=0 || count >=sizeof (temp) || count ==0 ) -return -EINVAL ; - -if (copy_from_user (temp, buf, count) !=0 ) -return -EFAULT ; + ret =kstrtos32_from_user (buf, count,10 , &i); +if (unlikely (ret)) +return ret; - temp[count] ='\0' ; - -if (sscanf (temp,"%d" , &i) !=1 ) -return -EINVAL ;if (i <SMACK_PTRACE_DEFAULT || i >SMACK_PTRACE_MAX )return -EINVAL ; smack_ptrace_rule = i;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 316/1376 smack: deduplicate smackfs/{direct,mapped} file_operations
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Konstantin Andreev <[email protected]>
[ Upstream commit 577dc3b6a8cf200e6e27b2d9967cac14a1fed2f3 ]
The file_operations for smackfs/direct and smackfs/mapped are identical up to a textual replacement of "direct" with "mapped"
This patch combines two instances of file_operations into one, handling both files.
--- security/smack/smack.h | 5 +- security/smack/smackfs.c | 133 ++++++++++++--------------------------- 2 files changed, 42 insertions(+), 96 deletions(-)
security/smack/smack.h +3 -2
@@ -302,8 +302,9 @@ int smack_populate_secattr(struct smack_known *skp);* Shared data. */ extern int smack_enabled__initdata ; -extern int smack_cipso_direct; -extern int smack_cipso_mapped; +extern int smack_cipso_auto_level[2 ]; +#define smack_cipso_direct (+smack_cipso_auto_level[0]) +#define smack_cipso_mapped (+smack_cipso_auto_level[1])extern struct smack_known *smack_net_ambient;extern struct smack_known *smack_syslog_label;#ifdef CONFIG_SECURITY_SMACK_BRINGUP
security/smack/smackfs.c +39 -94
206 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 317/1376 smack: restrict smackfs/{direct,mapped} values to 0-255
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Konstantin Andreev <[email protected]>
[ Upstream commit a7c44fd9f80e37763acf9cd3c87a58058d206427 ]
Both smackfs/direct and smackfs/mapped incorrectly accept the full range of integer values. For example:
# cd /sys/fs/smackfs/
# cat direct ; echo
250 # cat cipso2
@ 250/2
_ 250/2,4,5,6,7,8
* 250/3,5,7
^ 250/2,4,5,6,7
? 250/3,4,5,6,7,8 # echo -1234 >direct ; cat direct ; echo
-1234
# cat cipso2
@ -1234/2
_ -1234/2,4,5,6,7,8
* -1234/3,5,7
^ -1234/2,4,5,6,7
? -1234/3,4,5,6,7,8
#I noticed two things regarding this:
1) sensitivity levels are truncated to 8 bits when labeling outgoing packets (0x2e = 46 for the -1234 example above)
2) the reverse process fails: incoming packets with sensitivity level 46 do not match these smackfs/cipso2 entries.
Even observation (1) on its own warrants a fix.
This patch restricts smackfs/direct and smackfs/mapped accepted values to the 0-255 range.
--- security/smack/smack.h | 2 +- security/smack/smackfs.c | 26 ++++++++++++++------------ 2 files changed, 15 insertions(+), 13 deletions(-)
security/smack/smack.h +1 -1
@@ -302,7 +302,7 @@ int smack_populate_secattr(struct smack_known *skp);* Shared data. */ extern int smack_enabled__initdata ; -extern int smack_cipso_auto_level[2 ]; +extern u8 smack_cipso_auto_level[2 ];#define smack_cipso_direct (+smack_cipso_auto_level[0])#define smack_cipso_mapped (+smack_cipso_auto_level[1])extern struct smack_known *smack_net_ambient;
security/smack/smackfs.c +14 -12
@@ -92,7 +92,7 @@ struct smack_known *smack_net_ambient;* secid is contained directly in the category set. * It can be reset via smackfs/mapped */ -int smack_cipso_auto_level[2 ] = { +u8 smack_cipso_auto_level[2 ] = {SMACK_CIPSO_DIRECT_DEFAULT ,SMACK_CIPSO_MAPPED_DEFAULT , };
@@ -1659,17 +1659,15 @@ static const struct file_operations smk_doi_ops = {static ssize_t smk_read_cipso_auto_level (struct file *filp,char __user *buf,size_t count,loff_t *ppos) { -char temp[80 ]; -ssize_t rc; +char temp[sizeof "255" ]; +int n;if (*ppos !=0 )return 0 ; -sprintf (temp,"%d" , smack_cipso_auto_level[ -smk_cipso_auto_level_idx (filp)]); - rc =simple_read_from_buffer (buf, count, ppos, temp,strlen (temp)); - -return rc; + n =sprintf (temp,"%u" , (unsigned int )smack_cipso_auto_level[ +smk_cipso_auto_level_idx (filp)]); +return simple_read_from_buffer (buf, count, ppos, temp, n); }/**
@@ -1685,13 +1683,16 @@ static ssize_t smk_write_cipso_auto_level(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) { - struct smack_known *skp; -int i, ret, idx, old_lvl; + int ret, idx; +u8 i, old_lvl;if (!smack_privileged (CAP_MAC_ADMIN ))return -EPERM ; - - ret =kstrtos32_from_user (buf, count,10 , &i); +/* +* draft-ietf-cipso-ipsecurity-01 (CIPSO 2.2), 3.4.2.4: +* "Sensitivity Level is 1 octet in length. Its value is from 0 to 255" +*/ + ret =kstrtou8_from_user (buf, count,10 , &i);if (unlikely (ret))return ret;
@@ -1704,6 +1705,7 @@ smk_write_cipso_auto_level(struct file *filp, const char __user *buf, old_lvl = smack_cipso_auto_level[idx];if (old_lvl != i) { +struct smack_known *skp;mutex_lock (&smack_known_lock);list_for_each_entry_rcu (skp, &smack_known_list, list) if (skp->smk_netlabel.attr.mls.lvl ==
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 318/1376 sched_ext/scx_flatcg: Fix cvtime_delta race and add hweight scaling to bypass charging
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wanwu Li <[email protected]>
[ Upstream commit a5cc43414b38decd50bdd447e558358a6fbd5864 ]
1. cgrp_cap_budget() used __sync_fetch_and_sub(&cgc->cvtime_delta, cgc->cvtime_delta) to atomically read and clear cvtime_delta. However, this is not a true atomic read-clear operation: the second argument (cgc->cvtime_delta) is evaluated as a normal read before the atomic fetch_and_sub executes. If a concurrent __sync_fetch_and_add() happens between the read and the sub, the added value gets included in the returned delta AND remains in cvtime_delta, causing double charging.
Example:
CPU 0 runs cgrp_cap_budget(), CPU 1 runs fcg_stopping(). Assume cvtime_delta = 100 initially.
T1 CPU 0: sub_val = cvtime_delta = 100 cvtime_delta = 100
T2 CPU 1: __sync_fetch_and_add(&cvtime_delta, 10) cvtime_delta = 110
T3 CPU 0: __sync_fetch_and_sub(&cvtime_delta, sub_val) cvtime_delta = 10
returns old=110 delta = 110 (includes the 10 from CPU 1), but cvtime_delta = 10 (the 10 also remains). The 10 is charged twice: once in delta (applied to cgv_node->cvtime) and once in the residual cvtime_delta (fetched again next time).
Fix by using __sync_fetch_and_and(&cgc->cvtime_delta, 0). Disassembly comparison:
(1) delta = __sync_fetch_and_sub(&cgc->cvtime_delta, cgc->cvtime_delta); 228: (79) r7 = *(u64 *)(r9 +40)
229: (87) r7 = -r7
230: (db) r7 = atomic64_fetch_add((u64 *)(r9 +40), r7) //r9 may be changed
(2) delta = __sync_fetch_and_and(&cgc->cvtime_delta, 0); 228: (b7) r8 = 0 229: (db) r8 = atomic64_xchg((u64 *)(r9 +40), r8)
2. The bypass charging path in fcg_stopping() charges raw execution time to cvtime_delta without scaling by the inverse of the cgroup hweight. Since cvtime_delta is eventually applied to cgv_node->cvtime which is in vtime space (weight-scaled), the bypass path should also scale by FCG_HWEIGHT_ONE / hweight to match the units used by the dispatch path.
--- tools/sched_ext/scx_flatcg.bpf.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
tools/sched_ext/scx_flatcg.bpf.c +3 -2
@@ -261,7 +261,7 @@ static void cgrp_cap_budget(struct cgv_node *cgv_node, struct fcg_cgrp_ctx *cgc)* and thus can't be updated and repositioned. Instead, we collect the * vtime deltas separately and apply it asynchronously here. */ - delta =__sync_fetch_and_sub (&cgc->cvtime_delta, cgc->cvtime_delta); + delta =__sync_fetch_and_and (&cgc->cvtime_delta,0 ); cvtime = cgv_node->cvtime + delta;/*
@@ -571,7 +571,8 @@ void BPF_STRUCT_OPS(fcg_stopping, struct task_struct *p, bool runnable) cgc =find_cgrp_ctx (cgrp);if (cgc) {__sync_fetch_and_add (&cgc->cvtime_delta, - p->se.sum_exec_runtime - taskc->bypassed_at); + (p->se.sum_exec_runtime - taskc->bypassed_at) * +FCG_HWEIGHT_ONE / (cgc->hweight ?:1 )); taskc->bypassed_at =0 ; }bpf_cgroup_release (cgrp);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 319/1376 x86/cfi: Use symmetric SYM_START and SYM_END in __CFI_TYPE()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jens Remus <[email protected]>
[ Upstream commit 0cfdf974f133e0ff17ed80e7895adbe7889d9522 ]
Commit
ccace936eec7 ("x86: Add types to indirectly called assembly functions")
introduced a x86-specific implementation of __CFI_TYPE() using an asymmetric combination of SYM_START() and SYM_FUNC_END() to add a symbol to the KCFI type identifier that precedes a function.
This asymmetric combination is an issue if SYM_FUNC_END() ever gets extended in a way that requires it to be used symmetrically with SYM_FUNC_START*(). For instance to emit DWARF CFI directives that denote the start/end of a function. [1]
Use SYM_END() with SYM_T_FUNC instead. No functional change, as the generic implementation of SYM_FUNC_END(name) expands into SYM_END(name, SYM_T_FUNC).
--- arch/x86/include/asm/linkage.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/include/asm/linkage.h +1 -1
@@ -103,7 +103,7 @@ .byte 0xb8 ASM_NL \ .long __kcfi_typeid_##name ASM_NL \ CFI_POST_PADDING \ - SYM_FUNC_END(__cfi_##name) + SYM_END(__cfi_##name, SYM_T_FUNC)/* UML needs to be able to override memcpy() and friends for KASAN. */ #ifdef CONFIG_UML
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 320/1376 platform/chrome: cros_ec_typec: Reject out-of-bounds PD cap count
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maoyi Xie <[email protected]>
[ Upstream commit a0a8cd9fc9c48b95095bcec4b146f7a99486f58e ]
cros_typec_register_partner_pdos() copies the partner PDOs from the EC TYPEC_STATUS response into the fixed caps_desc.pdo[PDO_MAX_OBJECTS] array.
memcpy(caps_desc.pdo, resp->source_cap_pdos, sizeof(u32) * resp->source_cap_count); ... memcpy(caps_desc.pdo, resp->sink_cap_pdos, sizeof(u32) * resp->sink_cap_count);
PDO_MAX_OBJECTS is 7. source_cap_count and sink_cap_count are u8 fields from the EC. The only check is that they are not both zero. If either is larger than 7, the memcpy writes past the end of the array on the stack. A count of 255 overflows it by about 1 KB. The EC source arrays are only seven entries wide. A larger count reads past them too.
The ChromeOS EC firmware caps these counts today, so a compliant setup does not hit this. The kernel should still validate these values rather than trust them.
Validate the counts in cros_typec_register_partner_pdos() next to the memcpy. Skip the PDO registration if either count is above PDO_MAX_OBJECTS. The rest of cros_typec_handle_status() still runs so events are handled and cleared.
--- drivers/platform/chrome/cros_ec_typec.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/platform/chrome/cros_ec_typec.c +6 -0
@@ -989,6 +989,12 @@ static void cros_typec_register_partner_pdos(struct cros_typec_data *typec,if (!resp->source_cap_count && !resp->sink_cap_count)return ; +if (resp->source_cap_count >PDO_MAX_OBJECTS || + resp->sink_cap_count >PDO_MAX_OBJECTS ) { +dev_warn (typec->dev,"Invalid PDO count from EC, port: %d\n" , port_num); +return ; + } + port->partner_pd =typec_partner_usb_power_delivery_register (port->partner, &desc);if (IS_ERR (port->partner_pd)) {dev_warn (typec->dev,"Failed to register partner PD device, port: %d\n" , port_num);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 321/1376 HID: core: quiesce input in hid_hw_stop() to prevent use-after-free
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Philipp Weber <[email protected]>
[ Upstream commit a4bc41504690b7d7064931909874f5b98cd148b6 ]
A driver's probe calls hid_device_io_start() to enable input delivery, then fails at a later initialization step and unwinds via hid_hw_stop(). The unwind frees struct hidraw via hidraw_disconnect() while in-flight HID reports may still be running on another CPU, dereferencing the freed object through hidraw_report_event(). syzbot reports the resulting use-after-free for the corsair-psu HID driver.
Edward Adam Davis posted a per-driver fix for corsair-psu that adds an explicit hid_device_io_stop() before hid_hw_stop() in the probe error path ("hwmon: prevent packets from going to driver for probe", 2026-04-28). Auditing the tree shows 15 drivers call hid_device_io_start(); 7 also call hid_device_io_stop() and 8 do not:
drivers calling hid_device_io_start() without a matching hid_device_io_stop() before hid_hw_stop():
drivers/hwmon/corsair-psu.c (fix posted by Edward)
drivers/hwmon/corsair-cpro.c drivers/hwmon/nzxt-kraken3.c drivers/hwmon/nzxt-smart2.c drivers/hwmon/gigabyte_waterforce.c drivers/hid/hid-logitech-dj.c drivers/hid/hid-nintendo.c drivers/hid/hid-mcp2221.c
Roughly half of all callers of the API are exposed. Centralize the quiesce in hid_hw_stop() so callers do not have to remember the matching stop: if a driver has left hdev->io_started true on entry, call hid_device_io_stop() before hid_disconnect().
For the 7 drivers that already call hid_device_io_stop() correctly, hdev->io_started is false on entry, the guard short-circuits, and behavior is unchanged.
No Fixes: tag because the affected drivers gained their hid_device_io_start() calls independently over years; the bug is a class-wide API misuse rather than a regression from one commit.
--- drivers/hid/hid-core.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/hid/hid-core.c +7 -0
@@ -2423,9 +2423,16 @@ EXPORT_SYMBOL_GPL(hid_hw_start);* * This is usually called from remove function or from probe when something * failed and hid_hw_start was called already. +* +* If the caller enabled HID input via hid_device_io_start() and is unwinding +* without an explicit hid_device_io_stop(), quiesce input first so that +* in-flight reports cannot reach handlers (e.g. hidraw_report_event) whose +* backing objects hid_disconnect() is about to free. */ void hid_hw_stop (struct hid_device *hdev) { +if (hdev->io_started) +hid_device_io_stop (hdev);hid_disconnect (hdev); hdev->ll_driver->stop (hdev); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 322/1376 HID: nintendo: Fix imu_timestamp_us double increment per report
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christos Maragkos <[email protected]>
[ Upstream commit 1f9b25d3fb65b9384dec16d9db13a3e71abd9145 ]
Previously, the imu_timestamp_us variable was incremented twice per report, causing it to advance by two times the desired amount.
This resulted in incorrect jumps in IMU timestamps reported using MSC_TIMESTAMP, so userspace applications saw corrupted timing on functions such as gyroscope-based aim and motion controls.
This is fixed by removing the redundant increment at the start of the report handling so the remaining can account for the full report interval.
--- drivers/hid/hid-nintendo.c | 1 - 1 file changed, 1 deletion(-)
drivers/hid/hid-nintendo.c +0 -1
@@ -1457,7 +1457,6 @@ static void joycon_parse_imu_report(struct joycon_ctlr *ctlr, dropped_threshold = ctlr->imu_avg_delta_ms *3 /2 ; dropped_pkts = (delta -min (delta, dropped_threshold)) / ctlr->imu_avg_delta_ms; - ctlr->imu_timestamp_us +=1000 * ctlr->imu_avg_delta_ms;if (dropped_pkts >JC_IMU_DROPPED_PKT_WARNING ) { hid_warn(ctlr->hdev, "compensating for %u dropped IMU reports\n",
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 323/1376 HID: roccat: bound device-supplied profile index
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
[ Upstream commit 43fae42628a8c10fa8981773d7ec9f1a367821a7 ]
kone_keep_values_up_to_date() and kone_profile_activated() use an 8-bit, device-supplied profile value as an index into the 5-element kone->profiles[] array without a range check. A malicious USB device claiming the Roccat Kone id can send a switch-profile event (or a startup_profile read at probe) with an out-of-range value and make the driver read out of bounds; the result is exposed via the actual_dpi sysfs attribute.
Reject out-of-range indices in both paths.
This was found with static analysis and confirmed with the KUnit test added in the following patch (KASAN: slab-out-of-bounds).
--- drivers/hid/hid-roccat-kone.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/hid/hid-roccat-kone.c +6 -2
@@ -36,6 +36,8 @@ static uint profile_numbers[5] = {0, 1, 2, 3, 4};static void kone_profile_activated (struct kone_device *kone,uint new_profile) { +if (new_profile <1 || new_profile >ARRAY_SIZE (kone->profiles)) + new_profile =1 ; kone->actual_profile = new_profile; kone->actual_dpi = kone->profiles[new_profile -1 ].startup_dpi; }
@@ -793,8 +795,10 @@ static void kone_keep_values_up_to_date(struct kone_device *kone, {switch (event->event) {case kone_mouse_event_switch_profile: - kone->actual_dpi = kone->profiles[event->value -1 ]. - startup_dpi; +if (event->value >=1 && + event->value <=ARRAY_SIZE (kone->profiles)) + kone->actual_dpi = + kone->profiles[event->value -1 ].startup_dpi; fallthrough;case kone_mouse_event_osd_profile: kone->actual_profile = event->value;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 324/1376 soc: samsung: exynos-pmu: fix of_node refcount leak in exynos_get_pmu_regmap()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weigang He <[email protected]>
[ Upstream commit fa476d53edd24e8105faace04e881b9c4179738f ]
exynos_get_pmu_regmap() obtains a device_node via of_find_matching_node() and passes it to exynos_get_pmu_regmap_by_phandle(np, NULL). With propname == NULL the callee uses np directly and does not drop a reference, so the reference taken by of_find_matching_node() is leaked on every call -- including on each -EPROBE_DEFER retry of the only in-tree caller, exynos_retention_init() in the Exynos pinctrl driver.
Annotate np with the __free(device_node) cleanup attribute so the reference is released when the function returns.
Found by static analysis tool CodeQL.
--- drivers/soc/samsung/exynos-pmu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/soc/samsung/exynos-pmu.c +2 -2
@@ -276,8 +276,8 @@ static const struct mfd_cell exynos_pmu_devs[] = {*/ struct regmap *exynos_get_pmu_regmap (void ) { -struct device_node *np =of_find_matching_node (NULL , - exynos_pmu_of_device_ids); + struct device_node *np __free(device_node) = +of_find_matching_node (NULL , exynos_pmu_of_device_ids);if (np)return exynos_get_pmu_regmap_by_phandle (np,NULL );return ERR_PTR (-ENODEV );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 325/1376 media: cec-pin: Fix event FIFO ordering
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gui-Dong Han <[email protected]>
[ Upstream commit a1d83d1b810665bd53ce8a7b7867e054d68676c7 ]
cec_pin_update() fills work_pin_events[] and work_pin_ts[], then increments work_pin_num_events. cec_pin_thread_func() uses that counter to decide when to read the FIFO entries.
Do not let the counter update be observed without the event update. Also do not let a freed slot be reused before the thread has finished reading it. Use release operations when publishing an entry and releasing a slot, and acquire operations when consuming those counter updates.
Leave the other work_pin_num_events users as they do not participate in this FIFO publication path.
--- drivers/media/cec/core/cec-pin.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/media/cec/core/cec-pin.c +4 -4
@@ -114,7 +114,7 @@ static void cec_pin_update(struct cec_pin *pin, bool v, bool force)return ; pin->adap->cec_pin_is_high = v; -if (atomic_read (&pin->work_pin_num_events) <CEC_NUM_PIN_EVENTS ) { +if (atomic_read_acquire (&pin->work_pin_num_events) <CEC_NUM_PIN_EVENTS ) {u8 ev = v;if (pin->work_pin_events_dropped) {
@@ -125,7 +125,7 @@ static void cec_pin_update(struct cec_pin *pin, bool v, bool force) pin->work_pin_ts[pin->work_pin_events_wr] =ktime_get (); pin->work_pin_events_wr = (pin->work_pin_events_wr +1 ) %CEC_NUM_PIN_EVENTS ; -atomic_inc (&pin->work_pin_num_events); +atomic_inc_return_release (&pin->work_pin_num_events); }else { pin->work_pin_events_dropped = true; pin->work_pin_events_dropped_cnt++;
@@ -1074,7 +1074,7 @@ static int cec_pin_thread_func(void *_adap) pin->work_tx_ts); } -while (atomic_read (&pin->work_pin_num_events)) { +while (atomic_read_acquire (&pin->work_pin_num_events)) {unsigned int idx = pin->work_pin_events_rd;u8 v = pin->work_pin_events[idx];
@@ -1083,7 +1083,7 @@ static int cec_pin_thread_func(void *_adap) v &CEC_PIN_EVENT_FL_DROPPED , pin->work_pin_ts[idx]); pin->work_pin_events_rd = (idx +1 ) %CEC_NUM_PIN_EVENTS ; -atomic_dec (&pin->work_pin_num_events); +atomic_dec_return_release (&pin->work_pin_num_events); } switch (atomic_xchg(&pin->work_irq_change,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 326/1376 cxl: Refactor user ioctl command path from mds to mailbox
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dave Jiang <[email protected]>
[ Upstream commit 5666a7e7da2f003a8fc327d3c0cce0b506193d86 ]
With 'struct cxl_mailbox' context introduced, the helper functions cxl_query_cmd() and cxl_send_cmd() can take a cxl_mailbox directly rather than a cxl_memdev parameter. Refactor to use cxl_mailbox directly.
Stable-dep-of: 8a13db9f899d ("cxl/mbox: Clamp mailbox output allocation to the payload size")
--- drivers/cxl/core/core.h | 6 ++- drivers/cxl/core/mbox.c | 88 +++++++++++++++++++-------------------- drivers/cxl/core/memdev.c | 22 ++++++---- drivers/cxl/cxlmem.h | 40 ------------------ include/cxl/mailbox.h | 41 +++++++++++++++++- 5 files changed, 101 insertions(+), 96 deletions(-)
drivers/cxl/core/core.h +4 -2
@@ -4,6 +4,8 @@#ifndef __CXL_CORE_H__#define __CXL_CORE_H__ +#include <cxl/mailbox.h> +extern const struct device_type cxl_nvdimm_bridge_type;extern const struct device_type cxl_nvdimm_type;extern const struct device_type cxl_pmu_type;
@@ -65,9 +67,9 @@ static inline void cxl_region_exit(void)struct cxl_send_command ;struct cxl_mem_query_commands ; -int cxl_query_cmd (struct cxl_memdev *cxlmd, +int cxl_query_cmd (struct cxl_mailbox *cxl_mbox,struct cxl_mem_query_commands __user *q); -int cxl_send_cmd (struct cxl_memdev *cxlmd,struct cxl_send_command __user *s); +int cxl_send_cmd (struct cxl_mailbox *cxl_mbox,struct cxl_send_command __user *s);void __iomem *devm_cxl_iomap_block (struct device *dev,resource_size_t addr,resource_size_t length);
drivers/cxl/core/mbox.c +42 -46
240 lines not on this page · raw message
drivers/cxl/core/memdev.c +15 -7
@@ -564,9 +564,11 @@ EXPORT_SYMBOL_NS_GPL(is_cxl_memdev, CXL);void set_exclusive_cxl_commands (struct cxl_memdev_state *mds,unsigned long *cmds) { +struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox; +down_write (&cxl_memdev_rwsem); -bitmap_or (mds->exclusive_cmds, mds->exclusive_cmds, cmds, -CXL_MEM_COMMAND_ID_MAX ); +bitmap_or (cxl_mbox->exclusive_cmds, cxl_mbox->exclusive_cmds, + cmds,CXL_MEM_COMMAND_ID_MAX );up_write (&cxl_memdev_rwsem); }EXPORT_SYMBOL_NS_GPL (set_exclusive_cxl_commands,CXL );
@@ -579,9 +581,11 @@ EXPORT_SYMBOL_NS_GPL(set_exclusive_cxl_commands, CXL);void clear_exclusive_cxl_commands (struct cxl_memdev_state *mds,unsigned long *cmds) { +struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox; +down_write (&cxl_memdev_rwsem); -bitmap_andnot (mds->exclusive_cmds, mds->exclusive_cmds, cmds, -CXL_MEM_COMMAND_ID_MAX ); +bitmap_andnot (cxl_mbox->exclusive_cmds, cxl_mbox->exclusive_cmds, + cmds,CXL_MEM_COMMAND_ID_MAX );up_write (&cxl_memdev_rwsem); }EXPORT_SYMBOL_NS_GPL (clear_exclusive_cxl_commands,CXL );
@@ -656,11 +660,14 @@ static struct cxl_memdev *cxl_memdev_alloc(struct cxl_dev_state *cxlds,static long __cxl_memdev_ioctl (struct cxl_memdev *cxlmd,unsigned int cmd,unsigned long arg) { +struct cxl_memdev_state *mds =to_cxl_memdev_state (cxlmd->cxlds); +struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox; +switch (cmd) {case CXL_MEM_QUERY_COMMANDS : -return cxl_query_cmd (cxlmd, (void __user *)arg); +return cxl_query_cmd (cxl_mbox, (void __user *)arg);case CXL_MEM_SEND_COMMAND : -return cxl_send_cmd (cxlmd, (void __user *)arg); +return cxl_send_cmd (cxl_mbox, (void __user *)arg);default :return -ENOTTY ; }
@@ -994,10 +1001,11 @@ static void cxl_remove_fw_upload(void *fwl)int devm_cxl_setup_fw_upload (struct device *host,struct cxl_memdev_state *mds) {struct cxl_dev_state *cxlds = &mds->cxlds; +struct cxl_mailbox *cxl_mbox = &cxlds->cxl_mbox;struct device *dev = &cxlds->cxlmd->dev;struct fw_upload *fwl; -if (!test_bit (CXL_MEM_COMMAND_ID_GET_FW_INFO , mds->enabled_cmds)) +if (!test_bit (CXL_MEM_COMMAND_ID_GET_FW_INFO , cxl_mbox->enabled_cmds))return 0 ; fwl = firmware_upload_register(THIS_MODULE, dev, dev_name(dev),
drivers/cxl/cxlmem.h +0 -40
@@ -106,42 +106,6 @@ static inline struct cxl_ep *cxl_ep_load(struct cxl_port *port,return xa_load (&port->endpoints, (unsigned long )&cxlmd->dev); } -/** -* struct cxl_mbox_cmd - A command to be submitted to hardware. -* @opcode: (input) The command set and command submitted to hardware. -* @payload_in: (input) Pointer to the input payload. -* @payload_out: (output) Pointer to the output payload. Must be allocated by -* the caller. -* @size_in: (input) Number of bytes to load from @payload_in. -* @size_out: (input) Max number of bytes loaded into @payload_out. -* (output) Number of bytes generated by the device. For fixed size -* outputs commands this is always expected to be deterministic. For -* variable sized output commands, it tells the exact number of bytes -* written. -* @min_out: (input) internal command output payload size validation -* @poll_count: (input) Number of timeouts to attempt. -* @poll_interval_ms: (input) Time between mailbox background command polling -* interval timeouts. -* @return_code: (output) Error code returned from hardware. -* -* This is the primary mechanism used to send commands to the hardware. -* All the fields except @payload_* correspond exactly to the fields described in -* Command Register section of the CXL 2.0 8.2.8.4.5. @payload_in and -* @payload_out are written to, and read from the Command Payload Registers -* defined in CXL 2.0 8.2.8.4.8. -*/ -struct cxl_mbox_cmd { -u16 opcode; -void *payload_in; -void *payload_out; -size_t size_in; -size_t size_out; -size_t min_out; -int poll_count; -int poll_interval_ms; -u16 return_code; -}; -/* * Per CXL 3.0 Section 8.2.8.4.5.1 */
@@ -461,8 +425,6 @@ static inline struct cxl_dev_state *mbox_to_cxlds(struct cxl_mailbox *cxl_mbox)* @lsa_size: Size of Label Storage Area * (CXL 2.0 8.2.9.5.1.1 Identify Memory Device) * @firmware_version: Firmware version for the memory device. -* @enabled_cmds: Hardware commands found enabled in CEL. -* @exclusive_cmds: Commands that are kernel-internal only * @total_bytes: sum of all possible capacities * @volatile_only_bytes: hard volatile capacity * @persistent_only_bytes: hard persistent capacity
@@ -485,8 +447,6 @@ struct cxl_memdev_state {struct cxl_dev_state cxlds;size_t lsa_size;char firmware_version[0x10 ]; -DECLARE_BITMAP (enabled_cmds,CXL_MEM_COMMAND_ID_MAX ); -DECLARE_BITMAP (exclusive_cmds,CXL_MEM_COMMAND_ID_MAX );u64 total_bytes;u64 volatile_only_bytes;u64 persistent_only_bytes;
include/cxl/mailbox.h +40 -1
58 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 327/1376 cxl/mbox: Clamp mailbox output allocation to the payload size
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Richard Cheng <[email protected]>
[ Upstream commit 8a13db9f899d149c3aab24abcb668121cfda5a4f ]
CXL_MEM_SEND_COMMAND bounds the user's in.size to the mailbox payload size but leaves out.size unbounded, then cxl_mbox_cmd_ctor() calls kvzalloc(out.size). A large out.size drives a huge allocation, above INT_MAX it WARNs and taints, and with panic_on_warn=1 it panics.
The transport __cxl_pci_mbox_send_cmd() already clamps the response copy to min(out.size, payload_size, device len), so the output buffer is never written beyond payload_size. Clamp the allocation to payload_size too, matching the RAW path.
--- drivers/cxl/core/mbox.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-)
drivers/cxl/core/mbox.c +1 -5
@@ -372,11 +372,7 @@ static int cxl_mbox_cmd_ctor(struct cxl_mbox_cmd *mbox_cmd, } } -/* Prepare to handle a full payload for variable sized output */ -if (out_size ==CXL_VARIABLE_PAYLOAD ) - mbox_cmd->size_out = cxl_mbox->payload_size; -else - mbox_cmd->size_out = out_size; + mbox_cmd->size_out =min_t (size_t, out_size, cxl_mbox->payload_size);if (mbox_cmd->size_out) { mbox_cmd->payload_out =kvzalloc (mbox_cmd->size_out,GFP_KERNEL );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 328/1376 cxl/pci: Remove incorrect mbox.valid check in cxl_pci_type3_init_mailbox()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wei Hou <[email protected]>
[ Upstream commit d79b81893d0cc93737e811a465b9ef9a00156fd5 ]
The driver's design intent is that missing or malformed component registers should not prevent mailbox initialization. cxl_pci_probe() already reflects this: the CXL_REGLOC_RBI_COMPONENT setup path only emits a dev_warn() and continues when component registers are absent, rather than returning an error.
The check 'if (!cxlds->reg_map.device_map.mbox.valid)' violates this intent and is also technically incorrect for two reasons:
1. Wrong struct: the MEMDEV register block is enumerated into a local variable 'map', not into 'cxlds->reg_map'. The device_map.mbox.valid field inside cxlds->reg_map is never written by the MEMDEV probe and will always read as zero regardless of actual hardware capability.
2. Already validated: cxl_pci_setup_regs(CXL_REGLOC_RBI_MEMDEV) calls cxl_probe_regs() which explicitly checks mbox.valid and returns -ENXIO if the mailbox is absent. If that check passes, the mailbox is guaranteed to be present by the time cxl_pci_type3_init_mailbox() is called.
The value that the check actually reads is component_map.ras.valid, which aliases device_map.mbox.valid in the union. This is populated by the COMPONENT probe, not the MEMDEV probe. On devices where the component register BAR does not implement a CXL Component Capability Array (e.g. certain DCD devices), cxl_probe_component_regs() returns early leaving ras.valid=false. Through the union, this makes mbox.valid read as false, causing cxl_pci_type3_init_mailbox() to return -ENODEV (-19) even though the mailbox hardware is fully functional.
Remove the check. Mailbox presence has already been validated by cxl_pci_setup_regs(CXL_REGLOC_RBI_MEMDEV). The presence or absence of component registers is irrelevant to mailbox initialization.
--- drivers/cxl/pci.c | 6 ------ 1 file changed, 6 deletions(-)
drivers/cxl/pci.c +0 -6
@@ -794,12 +794,6 @@ static int cxl_pci_type3_init_mailbox(struct cxl_dev_state *cxlds) {int rc; -/* -* Fail the init if there's no mailbox. For a type3 this is out of spec. -*/ -if (!cxlds->reg_map.device_map.mbox.valid) -return -ENODEV ; - rc =cxl_mailbox_init (&cxlds->cxl_mbox, cxlds->dev);if (rc)return rc;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 329/1376 clk: versaclock7: Fix APLL clock leak on probe failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
[ Upstream commit e25d8d35e8cbc1a4c04a8b86eed6aa7229f6449e ]
vc7_probe() registers the APLL with clk_register_fixed_rate(), which is not devm-managed and must be explicitly unregistered on probe failure.
Most later errors already unwind through err_clk, but a failure from vc7_get_bank_clk() in the output registration loop returned directly. That skipped clk_unregister_fixed_rate() and leaked the APLL clock.
Route that error through the existing err_clk label so the fixed-rate clock is released consistently with the other probe failure paths.
This issue was identified during our ongoing static-analysis research while reviewing kernel code.
--- drivers/clk/clk-versaclock7.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/clk-versaclock7.c +1 -1
@@ -1191,7 +1191,7 @@ static int vc7_probe(struct i2c_client *client)if (ret) {dev_err_probe (&client->dev, ret,"unable to register output %d\n" , i); -return ret; + goto err_clk; }switch (bank_src_map.type) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 330/1376 clk: moxart: remove unused variables, fix refcount leak
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexander A. Klimov <[email protected]>
[ Upstream commit 9f275f2ee9ca60ea4c092bdc0195987945ad8ad8 ]
Not only these error checks are redundand,
those of_clk_get() return values weren't cleaned up via clk_put().
--- drivers/clk/clk-moxart.c | 14 -------------- 1 file changed, 14 deletions(-)
drivers/clk/clk-moxart.c +0 -14
@@ -17,7 +17,6 @@ static void __init moxart_of_pll_clk_init(struct device_node *node) {void __iomem *base;struct clk_hw *hw; -struct clk *ref_clk;unsigned int mul;const char *name = node->name;const char *parent_name;
@@ -34,12 +33,6 @@ static void __init moxart_of_pll_clk_init(struct device_node *node) mul =readl (base +0x30 ) >>3 &0x3f ;iounmap (base); - ref_clk =of_clk_get (node,0 ); -if (IS_ERR (ref_clk)) { -pr_err ("%pOF: of_clk_get failed\n" , node); -return ; - } - hw =clk_hw_register_fixed_factor (NULL , name, parent_name,0 , mul,1 );if (IS_ERR (hw)) {pr_err ("%pOF: failed to register clock\n" , node);
@@ -56,7 +49,6 @@ static void __init moxart_of_apb_clk_init(struct device_node *node) {void __iomem *base;struct clk_hw *hw; -struct clk *pll_clk;unsigned int div, val;unsigned int div_idx[] = {2 ,3 ,4 ,6 ,8 };const char *name = node->name;
@@ -78,12 +70,6 @@ static void __init moxart_of_apb_clk_init(struct device_node *node) val =0 ; div = div_idx[val] *2 ; - pll_clk =of_clk_get (node,0 ); -if (IS_ERR (pll_clk)) { -pr_err ("%pOF: of_clk_get failed\n" , node); -return ; - } - hw =clk_hw_register_fixed_factor (NULL , name, parent_name,0 ,1 , div);if (IS_ERR (hw)) {pr_err ("%pOF: failed to register clock\n" , node);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 331/1376 clk: nuvoton: ma35d1: fix ignored div_u64 return values in PLL freq calculation
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joey Lu <[email protected]>
[ Upstream commit b3a2223a7805c7e6759a32a5d6ca574ad07e2710 ]
div_u64() does not modify its argument in place; the return value must be assigned. Both ma35d1_calc_smic_pll_freq() and ma35d1_calc_pll_freq() called div_u64() and discarded the result, leaving pll_freq holding the undivided product and thus returning a frequency orders of magnitude too high.
--- drivers/clk/nuvoton/clk-ma35d1-pll.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/clk/nuvoton/clk-ma35d1-pll.c +2 -2
@@ -92,7 +92,7 @@ static unsigned long ma35d1_calc_smic_pll_freq(u32 pll0_ctl0, p =FIELD_GET (SPLL0_CTL0_OUTDIV , pll0_ctl0); outdiv =1 << p; pll_freq = (u64 )parent_rate * n; -div_u64 (pll_freq, m * outdiv); + pll_freq =div_u64 (pll_freq, m * outdiv);return pll_freq; }
@@ -110,7 +110,7 @@ static unsigned long ma35d1_calc_pll_freq(u8 mode, u32 *reg_ctl, unsigned long pif (mode ==PLL_MODE_INT ) { pll_freq = (u64 )parent_rate * n; -div_u64 (pll_freq, m * p); + pll_freq =div_u64 (pll_freq, m * p); }else { x =FIELD_GET (PLL_CTL1_FRAC , reg_ctl[1 ]);/* 2 decimal places floating to integer (ex. 1.23 to 123) */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 332/1376 clk: nuvoton: ma35d1: fix PLL_CTL1_FRAC bit field width and fractional calc
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joey Lu <[email protected]>
[ Upstream commit 26de5aed72d80bd8aec2583134aca3597c64fda9 ]
PLL_CTL1_FRAC was defined as GENMASK(31, 24), covering only 8 bits. The hardware fractional field occupies bits [31:8] (24 bits), so the mask must be GENMASK(31, 8).
The previous fractional-mode calculation used FIELD_MAX(PLL_CTL1_FRAC) as the denominator to obtain 2 decimal places. With the corrected 24-bit mask the old divisor is wrong; replace the arithmetic with a proper 24-bit fixed-point rounding to 3 decimal places using the kernel's DIV_ROUND_CLOSEST_ULL helper:
n_frac = n * 1000 + DIV_ROUND_CLOSEST_ULL(x * 1000, 1 << 24)
--- drivers/clk/nuvoton/clk-ma35d1-pll.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/clk/nuvoton/clk-ma35d1-pll.c +4 -4
@@ -48,7 +48,7 @@#define PLL_CTL1_PD BIT(0)#define PLL_CTL1_BP BIT(1)#define PLL_CTL1_OUTDIV GENMASK(6, 4) -#define PLL_CTL1_FRAC GENMASK(31, 24) +#define PLL_CTL1_FRAC GENMASK(31, 8)#define PLL_CTL2_SLOPE GENMASK(23, 0)#define INDIV_MIN 1
@@ -113,9 +113,9 @@ static unsigned long ma35d1_calc_pll_freq(u8 mode, u32 *reg_ctl, unsigned long p pll_freq =div_u64 (pll_freq, m * p); }else { x =FIELD_GET (PLL_CTL1_FRAC , reg_ctl[1 ]); -/* 2 decimal places floating to integer (ex. 1.23 to 123) */ - n = n *100 + ((x *100 ) /FIELD_MAX (PLL_CTL1_FRAC )); - pll_freq =div_u64 (parent_rate * n,100 * m * p); +/* convert 24-bit fraction to 3 decimal digits, rounding to closest */ + n = n *1000 +DIV_ROUND_CLOSEST_ULL ((u64 )x *1000 ,1ULL <<24 ); + pll_freq =div_u64 ((u64 )parent_rate * n,1000 * m * p); }return pll_freq; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 333/1376 clk: nuvoton: ma35d1-pll: convert from round_rate() to determine_rate()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Brian Masney <[email protected]>
[ Upstream commit cd9e9bbfd93be277e316ee854614e2c4cd502fa8 ]
The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch on the cover letter of this series.
Stable-dep-of: e1311954cb60 ("clk: nuvoton: ma35d1: fix ma35d1_clk_pll_determine_rate logic")
--- drivers/clk/nuvoton/clk-ma35d1-pll.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-)
drivers/clk/nuvoton/clk-ma35d1-pll.c +18 -10
@@ -244,35 +244,43 @@ static unsigned long ma35d1_clk_pll_recalc_rate(struct clk_hw *hw, unsigned longreturn 0 ; } -static long ma35d1_clk_pll_round_rate (struct clk_hw *hw,unsigned long rate, -unsigned long *parent_rate) +static int ma35d1_clk_pll_determine_rate (struct clk_hw *hw, +struct clk_rate_request *req) {struct ma35d1_clk_pll *pll =to_ma35d1_clk_pll (hw);u32 reg_ctl[3 ] = {0 };unsigned long pll_freq;long ret; -if (*parent_rate <PLL_FREF_MIN_FREQ || *parent_rate >PLL_FREF_MAX_FREQ ) +if (req->best_parent_rate <PLL_FREF_MIN_FREQ || req->best_parent_rate >PLL_FREF_MAX_FREQ )return -EINVAL ; - ret =ma35d1_pll_find_closest (pll, rate, *parent_rate, reg_ctl, &pll_freq); + ret =ma35d1_pll_find_closest (pll, req->rate, req->best_parent_rate, + reg_ctl, &pll_freq);if (ret <0 )return ret;switch (pll->id) {case CAPLL : reg_ctl[0 ] =readl_relaxed (pll->ctl0_base); - pll_freq =ma35d1_calc_smic_pll_freq (reg_ctl[0 ], *parent_rate); -return pll_freq; + pll_freq =ma35d1_calc_smic_pll_freq (reg_ctl[0 ], req->best_parent_rate); + req->rate = pll_freq; + +return 0 ;case DDRPLL :case APLL :case EPLL :case VPLL : reg_ctl[0 ] =readl_relaxed (pll->ctl0_base); reg_ctl[1 ] =readl_relaxed (pll->ctl1_base); - pll_freq =ma35d1_calc_pll_freq (pll->mode, reg_ctl, *parent_rate); -return pll_freq; + pll_freq =ma35d1_calc_pll_freq (pll->mode, reg_ctl, req->best_parent_rate); + req->rate = pll_freq; + +return 0 ; } + + req->rate =0 ; +return 0 ; }
@@ -311,12 +319,12 @@ static const struct clk_ops ma35d1_clk_pll_ops = { .unprepare = ma35d1_clk_pll_unprepare, .set_rate = ma35d1_clk_pll_set_rate, .recalc_rate = ma35d1_clk_pll_recalc_rate, - .round_rate = ma35d1_clk_pll_round_rate, + .determine_rate = ma35d1_clk_pll_determine_rate, };static const struct clk_ops ma35d1_clk_fixed_pll_ops = { .recalc_rate = ma35d1_clk_pll_recalc_rate, - .round_rate = ma35d1_clk_pll_round_rate, + .determine_rate = ma35d1_clk_pll_determine_rate, }; struct clk_hw *ma35d1_reg_clk_pll(struct device *dev, u32 id, u8 u8mode, const char *name,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 334/1376 clk: nuvoton: ma35d1: fix ma35d1_clk_pll_determine_rate logic
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joey Lu <[email protected]>
[ Upstream commit e1311954cb600d5f95cd9e2fe9a7376edc2ac3c5 ]
ma35d1_clk_pll_determine_rate() called ma35d1_pll_find_closest() unconditionally before the switch statement, and then every case branch overwrote pll_freq by reading the current hardware registers. For CAPLL and DDRPLL this means find_closest() ran unnecessarily (and incorrectly, since those PLLs are read-only) and its result was silently discarded.
Fix by moving the find_closest() call inside the APLL/EPLL/VPLL branch where it belongs. Group CAPLL and DDRPLL together as read-only PLLs that simply report their current rate; handle them with an explicit if/else to keep the CAPLL (SMIC design) and DDRPLL (standard design) paths distinct.
--- drivers/clk/nuvoton/clk-ma35d1-pll.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-)
drivers/clk/nuvoton/clk-ma35d1-pll.c +13 -13
@@ -255,32 +255,32 @@ static int ma35d1_clk_pll_determine_rate(struct clk_hw *hw,if (req->best_parent_rate <PLL_FREF_MIN_FREQ || req->best_parent_rate >PLL_FREF_MAX_FREQ )return -EINVAL ; - ret =ma35d1_pll_find_closest (pll, req->rate, req->best_parent_rate, - reg_ctl, &pll_freq); -if (ret <0 ) -return ret; -switch (pll->id) {case CAPLL : +case DDRPLL : +/* Read-only PLLs: return current rate */ reg_ctl[0 ] =readl_relaxed (pll->ctl0_base); - pll_freq =ma35d1_calc_smic_pll_freq (reg_ctl[0 ], req->best_parent_rate); +if (pll->id ==CAPLL ) { + pll_freq =ma35d1_calc_smic_pll_freq (reg_ctl[0 ], req->best_parent_rate); + }else { + reg_ctl[1 ] =readl_relaxed (pll->ctl1_base); + pll_freq =ma35d1_calc_pll_freq (pll->mode, reg_ctl, req->best_parent_rate); + } req->rate = pll_freq; -return 0 ; -case DDRPLL :case APLL :case EPLL :case VPLL : - reg_ctl[0 ] =readl_relaxed (pll->ctl0_base); - reg_ctl[1 ] =readl_relaxed (pll->ctl1_base); - pll_freq =ma35d1_calc_pll_freq (pll->mode, reg_ctl, req->best_parent_rate); +/* Configurable PLLs: find closest achievable rate */ + ret =ma35d1_pll_find_closest (pll, req->rate, req->best_parent_rate, + reg_ctl, &pll_freq); +if (ret <0 ) +return ret; req->rate = pll_freq; -return 0 ; } req->rate =0 ; -return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 335/1376 ASoC: rt700-sdw: always drain jack work on remove
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Runyu Xiao <[email protected]>
[ Upstream commit 612ccf42acd14bb2685fa60c3495ca13e63e8989 ]
rt700_sdw_remove() drains jack_detect_work and jack_btn_check_work only when rt700->hw_init is true. That state bit is cleared by rt700_update_status() when the SoundWire slave becomes UNATTACHED, but a jack work item can already have been queued by rt700_interrupt_callback() or rt700_jack_init() while the device was initialized.
Do not use hw_init as the remove-time guard for draining these work objects. The delayed works are initialized during rt700_init(), so remove can cancel them unconditionally and pair the object lifetime with the codec-private data lifetime instead of a mutable hardware state bit.
This issue was found by our static analysis tool and then confirmed by manual review of the SoundWire status, interrupt and remove paths. The remove path should drain work based on whether the work object exists, not on a runtime hardware state bit that can change after the work was queued.
A QEMU PoC queued jack_detect_work, simulated SDW_SLAVE_UNATTACHED, and then entered remove. DEBUG_OBJECTS reported an active timer/work object associated with the rt700 jack work path after remove skipped the cancel.
This is sent as an RFC because the practical trigger depends on SoundWire core remove ordering after an UNATTACHED status update. If remove cannot run after hw_init has been cleared while jack work is still pending, this is a defensive lifecycle cleanup rather than a reachable race on current systems.
--- sound/soc/codecs/rt700-sdw.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
sound/soc/codecs/rt700-sdw.c +2 -4
@@ -459,10 +459,8 @@ static int rt700_sdw_remove(struct sdw_slave *slave) {struct rt700_priv *rt700 =dev_get_drvdata (&slave->dev); -if (rt700->hw_init) { -cancel_delayed_work_sync (&rt700->jack_detect_work); -cancel_delayed_work_sync (&rt700->jack_btn_check_work); - } +cancel_delayed_work_sync (&rt700->jack_detect_work); +cancel_delayed_work_sync (&rt700->jack_btn_check_work);pm_runtime_disable (&slave->dev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 336/1376 ASoC: fsl_audmix: rework runtime PM handling in probe
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shengjiu Wang <[email protected]>
[ Upstream commit 3359ba93d01a23b2e4249e9e44ccfe48eb9c5d71 ]
After pm_runtime_enable() the AUDMIX block is powered off and stays suspended until the first runtime resume. Register writes issued between probe() and the first resume (e.g. from DAPM or ALSA control paths) target unpowered hardware and cause a system hang.
Fix this by calling pm_runtime_resume_and_get() immediately after pm_runtime_enable() to power the hardware up and enable its clocks. Release the reference afterwards with pm_runtime_put() to allow the runtime PM framework to suspend the device and switch the regmap to cache-only mode when idle.
When CONFIG_PM is disabled or runtime PM is not enabled, pm_runtime_* calls are stubs that do not power up the hardware. Handle this case explicitly by calling fsl_audmix_runtime_resume() directly so the hardware is always initialised and its clocks are enabled, ensuring register accesses succeed regardless of PM configuration.
--- sound/soc/fsl/fsl_audmix.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-)
sound/soc/fsl/fsl_audmix.c +22 -2
@@ -454,6 +454,9 @@ static const struct of_device_id fsl_audmix_ids[] = { };MODULE_DEVICE_TABLE (of, fsl_audmix_ids); +static int fsl_audmix_runtime_resume (struct device *dev); +static int fsl_audmix_runtime_suspend (struct device *dev); +static int fsl_audmix_probe (struct platform_device *pdev) {struct device *dev = &pdev->dev;
@@ -485,13 +488,25 @@ static int fsl_audmix_probe(struct platform_device *pdev)spin_lock_init (&priv->lock);platform_set_drvdata (pdev, priv);pm_runtime_enable (dev); +if (!pm_runtime_enabled (dev)) { + ret =fsl_audmix_runtime_resume (dev); +if (ret) + goto err_disable_pm; + } + + ret =pm_runtime_resume_and_get (dev); +if (ret <0 ) + goto err_pm_get_sync; + +/* To enable regmap cache only when runtime PM enabled */ +pm_runtime_put (dev); ret =devm_snd_soc_register_component (dev, &fsl_audmix_component, fsl_audmix_dai,ARRAY_SIZE (fsl_audmix_dai));if (ret) {dev_err (dev,"failed to register ASoC DAI\n" ); - goto err_disable_pm; + goto err_pm_get_sync; }/*
@@ -503,12 +518,15 @@ static int fsl_audmix_probe(struct platform_device *pdev)if (IS_ERR (priv->pdev)) { ret =PTR_ERR (priv->pdev);dev_err (dev,"failed to register platform: %d\n" , ret); - goto err_disable_pm; + goto err_pm_get_sync; } }return 0 ; +err_pm_get_sync: +if (!pm_runtime_status_suspended (dev)) +fsl_audmix_runtime_suspend (dev); err_disable_pm:pm_runtime_disable (dev);return ret;
@@ -519,6 +537,8 @@ static void fsl_audmix_remove(struct platform_device *pdev)struct fsl_audmix *priv =dev_get_drvdata (&pdev->dev);pm_runtime_disable (&pdev->dev); +if (!pm_runtime_status_suspended (&pdev->dev)) +fsl_audmix_runtime_suspend (&pdev->dev);if (priv->pdev)platform_device_unregister (priv->pdev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 337/1376 clk: hisilicon: reset: Use devm_kzalloc to initialize hisi_reset_controller
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Min zhang <[email protected]>
[ Upstream commit a8036f4591542de4b38ec81d3e2ba47bc0b2652b ]
Using devm_kmalloc() does not zero-initialize the allocated structure. Uninitialized members in struct hisi_reset_controller may contain garbage data, which can cause reset_controller_register() to fail unexpectedly.
Replace devm_kmalloc() with devm_kzalloc() to ensure all structure fields are properly zero-initialized.
--- drivers/clk/hisilicon/reset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/hisilicon/reset.c +1 -1
@@ -91,7 +91,7 @@ struct hisi_reset_controller *hisi_reset_init(struct platform_device *pdev) {struct hisi_reset_controller *rstc; - rstc =devm_kmalloc (&pdev->dev,sizeof (*rstc),GFP_KERNEL ); + rstc =devm_kzalloc (&pdev->dev,sizeof (*rstc),GFP_KERNEL );if (!rstc)return NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 338/1376 ARM: imx: fix device_node refcount leak in imx_src_init()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weigang He <[email protected]>
[ Upstream commit 936407c3563ac745cbbb9953c0cf2472128a22f4 ]
imx_src_init() obtains a device_node reference via of_find_compatible_node() matching "fsl,imx51-src" and uses it only to call of_iomap(). It never releases that reference: on the success path the function returns at the end without of_node_put(np), leaking one device_node refcount on every boot of an i.MX5/6 platform.
Release the reference right after of_iomap(). of_iomap() maps the node's registers but does not retain a reference to the device_node, so the node can be put once the mapping is done. The early return on a NULL np needs no put.
Found by static analysis tool CodeQL.
--- arch/arm/mach-imx/src.c | 1 + 1 file changed, 1 insertion(+)
arch/arm/mach-imx/src.c +1 -0
@@ -171,6 +171,7 @@ void __init imx_src_init(void)if (!np)return ; src_base =of_iomap (np,0 ); +of_node_put (np);WARN_ON (!src_base);/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 339/1376 ARM: imx: fix device_node refcount leaks in imx7_src_init()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weigang He <[email protected]>
[ Upstream commit 3de939b2ac843d56d88e2ab1e1b1f667cba9e1d4 ]
imx7_src_init() obtains two device_node references via of_find_compatible_node() - one for "fsl,imx7d-src" and one for "fsl,imx7d-gpc" - reusing the same np variable, but never calls of_node_put() on either. On every i.MX7D boot up to two device_node refcounts are leaked:
- The "fsl,imx7d-src" node is leaked both when of_iomap() fails (the early return after the mapping) and when it succeeds, because np is then overwritten by the second of_find_compatible_node() call without releasing the prior reference.
- The "fsl,imx7d-gpc" node is leaked on every path leaving the function after it is acquired.
Release each reference immediately after of_iomap() consumes the node. of_iomap() maps the node's registers but does not retain a reference to the device_node, so it is safe to put the node once mapped; this also drops the first reference before np is reused for the second lookup.
Found by static analysis tool CodeQL.
--- arch/arm/mach-imx/src.c | 2 ++ 1 file changed, 2 insertions(+)
arch/arm/mach-imx/src.c +2 -0
@@ -196,6 +196,7 @@ void __init imx7_src_init(void)return ; src_base =of_iomap (np,0 ); +of_node_put (np);if (!src_base)return ;
@@ -204,6 +205,7 @@ void __init imx7_src_init(void)return ; gpc_base =of_iomap (np,0 ); +of_node_put (np);if (!gpc_base)return ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 340/1376 arm64: dts: imx93-kontron: set memory node to 0x80000000/1GiB
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Frieder Schrempf <[email protected]>
[ Upstream commit 9c269fe7eae8cb60d8d6c326dd8955818722fae9 ]
The start address of the DRAM area is 0x80000000. The minimal size of the DDR on the SoM is 1 GiB.
--- arch/arm64/boot/dts/freescale/imx93-kontron-osm-s.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/arm64/boot/dts/freescale/imx93-kontron-osm-s.dtsi +2 -2
@@ -15,9 +15,9 @@ aliases { rtc1 = &bbnsm_rtc; }; - memory@40000000 { + memory@80000000 { device_type = "memory"; - reg = <0x0 0x40000000 0 0x80000000>; + reg = <0x0 0x80000000 0 0x40000000>; }; chosen {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 341/1376 clk: imx: scu: drop redundant init.ops variable assignment
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Brian Masney <[email protected]>
[ Upstream commit 5f2db1ce201216e81333ecc2ab51494410b2fe0d ]
The init.ops is assigned a default value, however right below it is an if, else if, and else where all of them also assign a value to init.ops. Drop the redundant init.ops assignment at the top.
--- drivers/clk/imx/clk-scu.c | 1 - 1 file changed, 1 deletion(-)
drivers/clk/imx/clk-scu.c +0 -1
@@ -483,7 +483,6 @@ struct clk_hw *__imx_clk_scu(struct device *dev, const char *name, clk->clk_type = clk_type; init.name = name; - init.ops = &clk_scu_ops;if (rsrc_id ==IMX_SC_R_A35 || rsrc_id ==IMX_SC_R_A53 || rsrc_id ==IMX_SC_R_A72 ) init.ops = &clk_scu_cpu_ops;else if (rsrc_id ==IMX_SC_R_PI_0_PLL )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 342/1376 drm/lima: call drm_mm_init() with a valid allocation range
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Henrik Grimler <[email protected]>
[ Upstream commit 3b3bce4a692ac60d9f4a341e6b597dd1fd0a28f9 ]
lima_vm_create() is currently run before va_start and va_end are set up, meaning they are both 0. lima_vm_create() runs drm_mm_init() with them as arguments for the allocator, and if DRM_DEBUG_MM is enabled the DRM_MM_BUG_ON check in drm_mm_init then fires, as seen here on exynos4412-odroid-u2:
[ 1.736297] ------------[ cut here ]------------ [ 1.740370] kernel BUG at drivers/gpu/drm/drm_mm.c:931! [ 1.745574] Internal error: Oops - BUG: 0 [#1] SMP ARM [ 1.750697] Modules linked in: [ 1.753734] CPU: 0 UID: 0 PID: 41 Comm: kworker/u16:1 Not tainted 7.0.10-postmarketos-exynos4 #11 PREEMPT [ 1.763372] Hardware name: Samsung Exynos (Flattened Device Tree) [ 1.769446] Workqueue: events_unbound deferred_probe_work_func [ 1.775261] PC is at drm_mm_init+0x9c/0xa4 [ 1.779339] LR is at lima_vm_create+0x144/0x17c
[ ... ]
Fix the issue by moving the lima_vm_create() call after va_start and va_end are set up.
--- drivers/gpu/drm/lima/lima_device.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/gpu/drm/lima/lima_device.c +6 -6
@@ -368,12 +368,6 @@ int lima_device_init(struct lima_device *ldev)if (err) goto err_out0; - ldev->empty_vm =lima_vm_create (ldev); -if (!ldev->empty_vm) { - err = -ENOMEM ; - goto err_out1; - } - ldev->va_start =0 ;if (ldev->id == lima_gpu_mali450) { ldev->va_end =LIMA_VA_RESERVE_START ;
@@ -387,6 +381,12 @@ int lima_device_init(struct lima_device *ldev) }else ldev->va_end =LIMA_VA_RESERVE_END ; + ldev->empty_vm =lima_vm_create (ldev); +if (!ldev->empty_vm) { + err = -ENOMEM ; + goto err_out1; + } + ldev->iomem =devm_platform_ioremap_resource (pdev,0 );if (IS_ERR (ldev->iomem)) {dev_err (ldev->dev,"fail to ioremap iomem\n" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 343/1376 mm/mm_init: fix incorrect node_spanned_pages
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wei Yang <[email protected]>
[ Upstream commit 7783dcd79ae9c4aa48bc47bd4275772445dc4b2a ]
Current node_spanned_pages is got as a summation of all zone's spanned page in calculate_node_totalpages(). Generally this is good, but if we use kernelcore=mirror, it is would be wrong.
Without kernelcore=mirror:
The test machine has below memory layout:
memory[0x0] [0x0000000000001000-0x000000000009efff], 0x000000000009e000 bytes on node 0 flags: 0x0
memory[0x1] [0x0000000000100000-0x00000000bffdefff], 0x00000000bfedf000 bytes on node 0 flags: 0x0
memory[0x2] [0x0000000100000000-0x00000001bfffffff], 0x00000000c0000000 bytes on node 0 flags: 0x0
And the Zone range is:
DMA [mem 0x0000000000001000-0x0000000000ffffff]
DMA32 [mem 0x0000000001000000-0x00000000ffffffff]
Normal [mem 0x0000000100000000-0x00000001bfffffff]
Then we see, with spanned_pages printed:
On node 0 spanned_pages: 1835007 totalpages: 1572733With kernelcore=mirror:
The test machine has below memory layout:
memory[0x0] [0x0000000000001000-0x000000000009efff], 0x000000000009e000 bytes on node 0 flags: 0x2
memory[0x1] [0x0000000000100000-0x00000000bffdefff], 0x00000000bfedf000 bytes on node 0 flags: 0x2
memory[0x2] [0x0000000100000000-0x000000013fffffff], 0x0000000040000000 bytes on node 0 flags: 0x2
memory[0x3] [0x0000000140000000-0x00000001bfffffff], 0x0000000080000000 bytes on node 0 flags: 0x0
And the Zone range is:
DMA [mem 0x0000000000001000-0x0000000000ffffff]
DMA32 [mem 0x0000000001000000-0x00000000ffffffff]
Normal [mem 0x0000000100000000-0x00000001bfffffff]
Device empty
Movable zone start for each node
Node 0: 0x0000000140000000
Then we see, with spanned_pages printed:
On node 0 spanned_pages: 2359295 totalpages: 1572733The total range of memory on node 0 doesn't change, but the spanned_pages becomes much larger.
The reason is when kernelcore=mirror is specified, the range of Zone Normal and Zone Movable would overlap. So the overlapped range would be calculated twice.
A wrong node_spanned_pages would effect defer_init(), since each zone_end_pfn is less than pgdat_end_pfn().
As we already passed in node_start_pfn and node_end_pfn, fix this by get it from (node_start_pfn - node_end_pfn) directly.
--- mm/mm_init.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
mm/mm_init.c +2 -3
@@ -1310,7 +1310,7 @@ static void __init calculate_node_totalpages(struct pglist_data *pgdat,unsigned long node_start_pfn, unsigned long node_end_pfn) { - unsigned long realtotalpages = 0, totalpages = 0; + unsigned long realtotalpages = 0;enum zone_type i;for (i =0 ; i <MAX_NR_ZONES ; i++) {
@@ -1340,11 +1340,10 @@ static void __init calculate_node_totalpages(struct pglist_data *pgdat, zone->present_early_pages = real_size;#endif - totalpages += spanned; realtotalpages += real_size; } - pgdat->node_spanned_pages = totalpages; + pgdat->node_spanned_pages = node_end_pfn - node_start_pfn; pgdat->node_present_pages = realtotalpages;pr_debug ("On node %d totalpages: %lu\n" , pgdat->node_id, realtotalpages); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 344/1376 sched/fair: Fix overflow in update_tg_cfs_runnable()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chen, Yu C <[email protected]>
[ Upstream commit 4f166adb5cb0525d9e32d45729fd8f28c80acbee ]
A divide-by-zero crash is observed when running hackbench:
[14697.488452] CPU: 112 UID: 0 PID: 124791 Comm: hackbench Not tainted 7.1.0-rc2+ [14697.492627] RIP: 0010:propagate_entity_load_avg+0x35f/0x3e0 [14697.506799] <TASK> [14697.507411] __dequeue_task+0x2b4/0xc70 [14697.508677] dequeue_task_fair+0x36/0x370 [14697.509047] dequeue_task+0x101/0x2f0 [14697.509426] __schedule+0x1b1/0x1a00 [14697.510868] anon_pipe_read+0x3da/0x450 [14697.511400] vfs_read+0x361/0x390 [14697.512053] __x64_sys_read+0x19/0x30
The divide-by-zero happens here:
if (scale_load_down(gcfs_rq->load.weight)) {
load_sum = div_u64(gcfs_rq->avg.load_sum,
scale_load_down(gcfs_rq->load.weight));
}gcfs_rq->load.weight is an insane large value and is truncated to the lower 32 bits by div_u64, which happen to be 0.
Using AI for investigation, the cause is a u32 overflow in update_tg_cfs_runnable(), and flat pickup became a victim when using tg_tasks():
u32 new_sum, divider;
...
new_sum = se->avg.runnable_avg * divider; <-- boom
The following sequence shows how this triggers the crash:
propagate_entity_load_avg()
update_tg_cfs_runnable() # u32 overflow corrupts runnable_sum
__update_load_avg_cfs_rq()
___update_load_avg() # computes insane runnable_avg
update_tg_load_avg() # propagates to tg->runnable_avg
update_cfs_group()
calc_concur_shares()
tg_tasks() # long-to-int truncation, negative nr
reweight_entity() # corrupted se->load.weight
update_load_add() # corrupted cfs_rq->load.weight propagate_entity_load_avg()
update_tg_cfs_load()
div_u64() # divide-by-zero
Fix by widening new_sum from u32 to u64 (no need to force tg_tasks() to return unsigned long after this fix)
--- kernel/sched/fair.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
kernel/sched/fair.c +3 -2
@@ -4416,7 +4416,8 @@ static inline void update_tg_cfs_runnable(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cfs_rq *gcfs_rq) { long delta_sum, delta_avg = gcfs_rq->avg.runnable_avg - se->avg.runnable_avg; -u32 new_sum, divider; +u64 new_sum; +u32 divider;/* Nothing to update */ if (!delta_avg)
@@ -4430,7 +4431,7 @@ update_tg_cfs_runnable(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cf/* Set new sched_entity's runnable */ se->avg.runnable_avg = gcfs_rq->avg.runnable_avg; - new_sum = se->avg.runnable_avg * divider; + new_sum = (u64 )se->avg.runnable_avg * divider; delta_sum = (long )new_sum - (long )se->avg.runnable_sum; se->avg.runnable_sum = new_sum;
Signature · 1 line
2.53.0
Re: [PATCH 6.12 0344/1376] sched/fair: Fix overflow in update_tg_cfs_runnable()
Hi Greg/Sasha,
Quoted 86 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chen, Yu C <[email protected]>
[ Upstream commit
4f166adb5cb0525d9e32d45729fd8f28c80acbee]A divide-by-zero crash is observed when running hackbench:
[14697.488452] CPU: 112 UID: 0 PID: 124791 Comm: hackbench Not tainted 7.1.0-rc2+ [14697.492627] RIP: 0010:propagate_entity_load_avg+0x35f/0x3e0 [14697.506799] <TASK> [14697.507411] __dequeue_task+0x2b4/0xc70 [14697.508677] dequeue_task_fair+0x36/0x370 [14697.509047] dequeue_task+0x101/0x2f0 [14697.509426] __schedule+0x1b1/0x1a00 [14697.510868] anon_pipe_read+0x3da/0x450 [14697.511400] vfs_read+0x361/0x390 [14697.512053] __x64_sys_read+0x19/0x30The divide-by-zero happens here:
if (scale_load_down(gcfs_rq->load.weight)) { load_sum = div_u64(gcfs_rq->avg.load_sum, scale_load_down(gcfs_rq->load.weight)); }
gcfs_rq->load.weightis an insane large value and is truncated to the lower 32 bits bydiv_u64, which happen to be 0.Using AI for investigation, the cause is a u32 overflow in
update_tg_cfs_runnable(), and flat pickup became a victim when usingtg_tasks():u32 new_sum, divider; ... new_sum = se->avg.runnable_avg * divider; <-- boomThe following sequence shows how this triggers the crash:
propagate_entity_load_avg()
update_tg_cfs_runnable()# u32 overflow corruptsrunnable_sum
__update_load_avg_cfs_rq()
___update_load_avg()# computes insanerunnable_avg
update_tg_load_avg()# propagates totg->runnable_avg
update_cfs_group()
calc_concur_shares()
tg_tasks()# long-to-int truncation, negative nr
reweight_entity()# corruptedse->load.weight
update_load_add()# corruptedcfs_rq->load.weight
propagate_entity_load_avg()
update_tg_cfs_load()
div_u64()# divide-by-zeroFix by widening
new_sumfrom u32 to u64 (no need to forcetg_tasks()to return unsigned long after this fix)Fixes 95246d1ec80b ("sched/pelt: Relax the sync of runnable_sum with runnable_avg")Assisted-by Claude:claude-opus-4.6Signed-off-by Chen Yu <[email protected]>Signed-off-by Peter Zijlstra (Intel) <[email protected]>Signed-off-by Sasha Levin <[email protected]>--- kernel/sched/fair.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)kernel/sched/fair.c +2
-1@@ -4416,7 +4416,8 @@ static inline void update_tg_cfs_runnable(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cfs_rq *gcfs_rq) { long delta_sum, delta_avg = gcfs_rq->avg.runnable_avg - se->avg.runnable_avg; -u32 new_sum, divider; +u64 new_sum; +u32 divider;/* Nothing to update */ if (!delta_avg)
kernel/sched/fair.c update_tg_cfs_runnable(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cf · line 4434
Quoted 5 lines
kernel/sched/fair.c +1
-1@@ -4430,7 +4431,7 @@ update_tg_cfs_runnable(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cf/* Set new sched_entity's runnable */ se->avg.runnable_avg = gcfs_rq->avg.runnable_avg; - new_sum = se->avg.runnable_avg * divider; + new_sum = (u64 )se->avg.runnable_avg * divider;
I ran an AI-assisted backport review, and I have verified the report. It looks valid to me.
The two posted hunks widen new_sum and the multiplication to u64. The 6.12 implementation then updates the parent runnable_sum through max_t(u32, ...), which explicitly recasts both operands to u32. The high bits fixed by this patch are therefore discarded during propagation to the parent cfs_rq.
Upstream code after 089d84203ad42:
__update_sa(&cfs_rq->avg, runnable, delta_avg, delta_sum);
Downstream 6.12.y code:
cfs_rq->avg.runnable_sum =
max_t(u32, cfs_rq->avg.runnable_sum,
cfs_rq->avg.runnable_avg * PELT_MIN_DIVIDER);The explicit downstream u32 conversion discards the widened high bits.
Upstream preserves the field type through __update_sa(), introduced by089d84203ad42 . Maybe we need to be adding a minimal 6.12 adaptation that clamps the parent runnable_sum as u64 before retaining this patch. Thoughts?
thanks,
Harshit
Quoted 3 lines
kernel/sched/fair.c +0
-0delta_sum = (long )new_sum - (long )se->avg.runnable_sum; se->avg.runnable_sum = new_sum;
Re: [PATCH 6.12 0344/1376] sched/fair: Fix overflow in update_tg_cfs_runnable()
Hi Harshit,
Quoted 112 lines · Harshit Mogalapalli
Hi Greg/Sasha,
Quoted 86 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chen, Yu C <[email protected]>
[ Upstream commit
4f166adb5cb0525d9e32d45729fd8f28c80acbee]A divide-by-zero crash is observed when running hackbench:
[14697.488452] CPU: 112 UID: 0 PID: 124791 Comm: hackbench Not tainted 7.1.0-rc2+ [14697.492627] RIP: 0010:propagate_entity_load_avg+0x35f/0x3e0 [14697.506799] <TASK> [14697.507411] __dequeue_task+0x2b4/0xc70 [14697.508677] dequeue_task_fair+0x36/0x370 [14697.509047] dequeue_task+0x101/0x2f0 [14697.509426] __schedule+0x1b1/0x1a00 [14697.510868] anon_pipe_read+0x3da/0x450 [14697.511400] vfs_read+0x361/0x390 [14697.512053] __x64_sys_read+0x19/0x30The divide-by-zero happens here:
if (
scale_load_down(gcfs_rq->load.weight)) {
load_sum=div_u64(gcfs_rq->avg.load_sum, scale_load_down(gcfs_rq->load.weight)); }
gcfs_rq->load.weightis an insane large value and is truncated to the lower 32 bits bydiv_u64, which happen to be 0.Using AI for investigation, the cause is a u32 overflow in
update_tg_cfs_runnable(), and flat pickup became a victim when usingtg_tasks():u32
new_sum, divider;
...
new_sum=se->avg.runnable_avg* divider; <-- boomThe following sequence shows how this triggers the crash:
propagate_entity_load_avg()
update_tg_cfs_runnable() # u32 overflow corruptsrunnable_sum
__update_load_avg_cfs_rq()
___update_load_avg() # computes insanerunnable_avgupdate_tg_load_avg() # propagates totg->runnable_avg
update_cfs_group()
calc_concur_shares()
tg_tasks() # long-to-int truncation, negative nr reweight_entity() # corruptedse->load.weightupdate_load_add() # corruptedcfs_rq->load.weight
propagate_entity_load_avg()update_tg_cfs_load()
div_u64() # divide-by-zeroFix by widening
new_sumfrom u32 to u64 (no need to forcetg_tasks()to return unsigned long after this fix)Fixes 95246d1ec80b ("sched/pelt: Relax the sync of runnable_sum with runnable_avg")Assisted-by Claude:claude-opus-4.6Signed-off-by Chen Yu <[email protected]>Signed-off-by Peter Zijlstra (Intel) <[email protected]>Signed-off-by Sasha Levin <[email protected]>---
kernel/sched/fair.c| 5 +++--1 file changed, 3 insertions(+), 2 deletions(-)kernel/sched/fair.c +0
-0@@ -4416,7 +4416,8 @@ static inline void update_tg_cfs_runnable(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cfs_rq *gcfs_rq) {long
delta_sum,delta_avg=gcfs_rq->avg.runnable_avg- se-Quoted 1 line
avg.runnable_avg;
- u32
new_sum, divider;
+ u64new_sum;
+ u32 divider;
/* Nothing to update */
if (!delta_avg)kernel/sched/fair.c +0
-0@@ -4430,7 +4431,7 @@ update_tg_cfs_runnable(struct cfs_rq *cfs_rq,Quoted 5 lines
struct
sched_entity*se, struct cf
/* Set new sched_entity's runnable */se->avg.runnable_avg=gcfs_rq->avg.runnable_avg; -new_sum=se->avg.runnable_avg* divider; +new_sum= (u64)se->avg.runnable_avg * divider;I ran an AI-assisted backport review, and I have verified the report. It looks valid to me.
The two posted hunks widen
new_sumand the multiplication to u64. The 6.12 implementation then updates the parentrunnable_sumthroughmax_t(u32, ...), which explicitly recasts both operands to u32. The high bits fixed by this patch are therefore discarded during propagation to the parentcfs_rq.Upstream code after
089d84203ad42:
__update_sa(&cfs_rq->avg, runnable, delta_avg, delta_sum);Downstream 6.12.y code:
Quoted 9 lines
cfs_rq->avg.runnable_sum=
max_t(u32, cfs_rq->avg.runnable_sum, cfs_rq->avg.runnable_avg * PELT_MIN_DIVIDER);The explicit downstream u32 conversion discards the widened high bits.
Upstream preserves the field type through
__update_sa(), introduced by089d84203ad42. Maybe we need to be adding a minimal 6.12 adaptation that clamps the parentrunnable_sumas u64 before retaining this patch. Thoughts?
It seems that in 6.12 update_tg_cfs_load() also has the risk of cutting u64 into u32, as load_sum is unbounded:
cfs_rq->avg.load_sum = max_t(u32, cfs_rq->avg.load_sum,
cfs_rq->avg.load_avg * PELT_MIN_DIVIDER);
either we could change the u32 into u64 for them, or maybe we can backport 089d84203ad42?
thanks,
Chenyu
Greg Kroah-Hartman
maintainerPATCH 345/1376 perf/x86/intel/uncore: Keep PCI PMUs working when MMIO/MSR setup fails
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zide Chen <[email protected]>
[ Upstream commit 3012af7df3430788eddd30b3c6654d0a0a5f06c6 ]
uncore_event_cpu_online() returns -ENOMEM early when both the MSR and MMIO box allocations fail. This also aborts PCI uncore setup, even though PCI PMUs are independent of the MSR/MMIO paths.
Remove the early return so PCI uncore setup always runs regardless of whether MSR or MMIO box allocation succeeds.
--- arch/x86/events/intel/uncore.c | 2 -- 1 file changed, 2 deletions(-)
arch/x86/events/intel/uncore.c +0 -2
@@ -1629,8 +1629,6 @@ static int uncore_event_cpu_online(unsigned int cpu) die =topology_logical_die_id (cpu); msr_ret =uncore_box_ref (uncore_msr_uncores, die, cpu); mmio_ret =uncore_box_ref (uncore_mmio_uncores, die, cpu); -if (msr_ret && mmio_ret) -return -ENOMEM ;/* * Check if there is an online cpu in the package
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 346/1376 pinctrl: bcm2835: Dont remove an unregistered GPIO chip
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daniel McCarthy <[email protected]>
[ Upstream commit 32711f77db0641e57fd96fdc013bf1286b9f2514 ]
If the devm_pinctrl_register() function fails, bcm2835_pinctrl_probe() calls gpiochip_remove() before gpiochip_add_data() has registered the GPIO chip.
This means that upon failure the gpio_chip.gpiodev
is NULL resulting in a null pointer dereference
inside the gpiochip_remove() function.
Remove the unnecessary function call to gpiochip_remove(). No GPIO cleanup is required because the GPIO chip has not yet been registered. Without this change there is potential for a kernel panic upon registration failure
--- drivers/pinctrl/bcm/pinctrl-bcm2835.c | 1 - 1 file changed, 1 deletion(-)
drivers/pinctrl/bcm/pinctrl-bcm2835.c +0 -1
@@ -1348,7 +1348,6 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev) pc->pctl_desc = *pdata->pctl_desc; pc->pctl_dev =devm_pinctrl_register (dev, &pc->pctl_desc, pc);if (IS_ERR (pc->pctl_dev)) { -gpiochip_remove (&pc->gpio_chip);return PTR_ERR (pc->pctl_dev); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 347/1376 riscv: kexec_file: Split the loading of kernel and others
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Song Shuai <[email protected]>
[ Upstream commit 1df45f8a9fea5a7513bd1bad98604ce1fbefcaaf ]
This is the preparative patch for kexec_file_load Image support.
It separates the elf_kexec_load() as two parts:
- the first part loads the vmlinux (or Image)
- the second part loads other segments (e.g. initrd,fdt,purgatory)
And the second part is exported as the load_extra_segments() function which would be used in both kexec-elf.c and kexec-image.c.
No functional change intended.
Stable-dep-of: 5fc6e7d45373 ("riscv: kexec_file: Fix crashk_low_res not exclude bug")
--- arch/riscv/include/asm/kexec.h | 5 + arch/riscv/kernel/Makefile | 2 +- arch/riscv/kernel/elf_kexec.c | 485 ------------------------- arch/riscv/kernel/kexec_elf.c | 144 ++++++++ arch/riscv/kernel/machine_kexec_file.c | 360 ++++++++++++++++++ 5 files changed, 510 insertions(+), 486 deletions(-) delete mode 100644 arch/riscv/kernel/elf_kexec.c create mode 100644 arch/riscv/kernel/kexec_elf.c
arch/riscv/include/asm/kexec.h +5 -0
@@ -67,6 +67,11 @@ int arch_kexec_apply_relocations_add(struct purgatory_info *pi,struct kimage ;int arch_kimage_file_post_load_cleanup (struct kimage *image);#define arch_kimage_file_post_load_cleanup arch_kimage_file_post_load_cleanup + +int load_extra_segments (struct kimage *image,unsigned long kernel_start, +unsigned long kernel_len,char *initrd, +unsigned long initrd_len,char *cmdline, +unsigned long cmdline_len);#endif #endif
arch/riscv/kernel/Makefile +1 -1
@@ -106,7 +106,7 @@ obj-$(CONFIG_HOTPLUG_CPU) += cpu-hotplug.o obj-$(CONFIG_PARAVIRT) += paravirt.o obj-$(CONFIG_KGDB) += kgdb.o obj-$(CONFIG_KEXEC_CORE) += kexec_relocate.o crash_save_regs.o machine_kexec.o -obj-$(CONFIG_KEXEC_FILE) += elf_kexec.o machine_kexec_file.o +obj-$(CONFIG_KEXEC_FILE) += kexec_elf.o machine_kexec_file.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_VMCORE_INFO) += vmcore_info.o
arch/riscv/kernel/elf_kexec.c deleted +0 -485
485 lines not on this page · raw message
arch/riscv/kernel/kexec_elf.c new file +144 -0
144 lines not on this page · raw message
arch/riscv/kernel/machine_kexec_file.c +360 -0
368 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 348/1376 riscv: kexec_file: Fix crashk_low_res not exclude bug
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jinjie Ruan <[email protected]>
[ Upstream commit 5fc6e7d45373571d03cd04fd4c6069c0a97fa75a ]
As done in commit 944a45abfabc ("arm64: kdump: Reimplement crashkernel=X") and commit 4831be702b95 ("arm64/kexec: Fix missing extra range for crashkres_low.") for arm64, while implementing crashkernel=X,[high,low], riscv should have excluded the "crashk_low_res" reserved ranges from the crash kernel memory to prevent them from being exported through /proc/vmcore, and the exclusion would need an extra crash_mem range.
Just simply tested on qemu with crashkernel=4G with kexec in [1] mentioned in [2]. And the second kernel can be started normally.
# dmesg | grep crash [ 0.000000] crashkernel low memory reserved: 0xf8000000 - 0x100000000 (128 MB) [ 0.000000] crashkernel reserved: 0x000000017fe00000 - 0x000000027fe00000 (4096 MB)
[1]: https://github.com/chenjh005/kexec-tools/tree/build-test-riscv-v2
[2]: https://lore.kernel.org/all/[email protected]/
--- arch/riscv/kernel/machine_kexec_file.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
arch/riscv/kernel/machine_kexec_file.c +11 -3
@@ -59,7 +59,7 @@ static int prepare_elf_headers(void **addr, unsigned long *sz)unsigned int nr_ranges;int ret; - nr_ranges =1 ;/* For exclusion of crashkernel region */ + nr_ranges =2 ;/* For exclusion of crashkernel region */ walk_system_ram_res (0 ,-1 , &nr_ranges, get_nr_ram_ranges_callback); cmem =kmalloc (struct_size (cmem, ranges, nr_ranges),GFP_KERNEL );
@@ -74,8 +74,16 @@ static int prepare_elf_headers(void **addr, unsigned long *sz)/* Exclude crashkernel region */ ret =crash_exclude_mem_range (cmem, crashk_res.start, crashk_res.end); -if (!ret) - ret =crash_prepare_elf64_headers (cmem, true, addr, sz); +if (ret) + goto out; + +if (crashk_low_res.end) { + ret =crash_exclude_mem_range (cmem, crashk_low_res.start, crashk_low_res.end); +if (ret) + goto out; + } + + ret =crash_prepare_elf64_headers (cmem, true, addr, sz); out:kfree (cmem);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 349/1376 media: keymaps: Remove obsolete RC_MAP_RC5_TV keymap define
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Young <[email protected]>
[ Upstream commit 5370facb7b4461166a4610d456fefeb92ef50a82 ]
Since commit 206241069ecf ("[media] rc/keymaps: Remove the obsolete rc-rc5-tv keymap"), the rc-rc5-tv keymap is no longer in the tree.
--- include/media/rc-map.h | 1 - 1 file changed, 1 deletion(-)
include/media/rc-map.h +0 -1
@@ -309,7 +309,6 @@ struct rc_map *rc_map_get(const char *name);#define RC_MAP_PROTEUS_2309 "rc-proteus-2309"#define RC_MAP_PURPLETV "rc-purpletv"#define RC_MAP_PV951 "rc-pv951" -#define RC_MAP_RC5_TV "rc-rc5-tv"#define RC_MAP_RC6_MCE "rc-rc6-mce"#define RC_MAP_REAL_AUDIO_220_32_KEYS "rc-real-audio-220-32-keys"#define RC_MAP_REDDO "rc-reddo"
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 350/1376 media: keymaps: Remove obsolete RC_MAP_HAUPPAUGE_NEW keymap define
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Young <[email protected]>
[ Upstream commit 6e5deb2923b0d1b73c77a1a77c30b0da43d9e022 ]
Since commit af86ce79f020 ("[media] remove the old RC_MAP_HAUPPAUGE_NEW RC map"), the RC_MAP_HAUPPAUGE_NEW define is no longer used.
--- include/media/rc-map.h | 1 - 1 file changed, 1 deletion(-)
include/media/rc-map.h +0 -1
@@ -262,7 +262,6 @@ struct rc_map *rc_map_get(const char *name);#define RC_MAP_GENIUS_TVGO_A11MCE "rc-genius-tvgo-a11mce"#define RC_MAP_GOTVIEW7135 "rc-gotview7135"#define RC_MAP_HAUPPAUGE "rc-hauppauge" -#define RC_MAP_HAUPPAUGE_NEW "rc-hauppauge"#define RC_MAP_HISI_POPLAR "rc-hisi-poplar"#define RC_MAP_HISI_TV_DEMO "rc-hisi-tv-demo"#define RC_MAP_IMON_MCE "rc-imon-mce"
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 351/1376 perf test: Update all metrics test like metricgroups test
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namhyung Kim <[email protected]>
[ Upstream commit e2cb1db7daf8b7863aeec07bb574d3fae54518e6 ]
Like in the metricgroup tests, it should check the permission first and then skip relevant failures accordingly.
Also it needs to try again with the system wide flag properly. On the second round, check if the result has the metric name because other failure cases are checked in the first round already.
Stable-dep-of: 8953bfd8820b ("perf tests: Skip metrics validation if system-wide recording lacks permission")
--- tools/perf/tests/shell/stat_all_metrics.sh | 87 ++++++++++++++++------ 1 file changed, 66 insertions(+), 21 deletions(-)
tools/perf/tests/shell/stat_all_metrics.sh +66 -21
@@ -2,42 +2,87 @@ # perf all metrics test # SPDX-License-Identifier: GPL-2.0 +ParanoidAndNotRoot() +{ + [ "$(id -u)" != 0 ] && [ "$(cat /proc/sys/kernel/perf_event_paranoid)" -gt $1 ] +} + +system_wide_flag="-a" +if ParanoidAndNotRoot 0 +then + system_wide_flag="" +fi + err=0 for m in $(perf list --raw-dump metrics); do echo "Testing $m" - result=$(perf stat -M "$m" true 2>&1) - if [[ "$result" =~ ${m:0:50} ]] || [[ "$result" =~ "<not supported>" ]] + result=$(perf stat -M "$m" $system_wide_flag -- sleep 0.01 2>&1) + result_err=$? + if [[ $result_err -gt 0 ]] then - continue + if [[ "$result" =~ \ + "Access to performance monitoring and observability operations is limited" ]] + then + echo "Permission failure" + echo $result + if [[ $err -eq 0 ]] + then + err=2 # Skip + fi + continue + elif [[ "$result" =~ "in per-thread mode, enable system wide" ]] + then + echo "Permissions - need system wide mode" + echo $result + if [[ $err -eq 0 ]] + then + err=2 # Skip + fi + continue + elif [[ "$result" =~ "<not supported>" ]] + then + echo "Not supported events" + echo $result + if [[ $err -eq 0 ]] + then + err=2 # Skip + fi + continue + elif [[ "$result" =~ "FP_ARITH" || "$result" =~ "AMX" ]] + then + echo "FP issues" + echo $result + if [[ $err -eq 0 ]] + then + err=2 # Skip + fi + continue + elif [[ "$result" =~ "PMM" ]] + then + echo "Optane memory issues" + echo $result + if [[ $err -eq 0 ]] + then + err=2 # Skip + fi + continue + fi fi - # Failed so try system wide. - result=$(perf stat -M "$m" -a sleep 0.01 2>&1) + if [[ "$result" =~ ${m:0:50} ]] then continue fi - # Failed again, possibly the workload was too small so retry with something - # longer. - result=$(perf stat -M "$m" perf bench internals synthesize 2>&1) + + # Failed, possibly the workload was too small so retry with something longer. + result=$(perf stat -M "$m" $system_wide_flag -- perf bench internals synthesize 2>&1) if [[ "$result" =~ ${m:0:50} ]] then continue fi echo "Metric '$m' not printed in:" echo "$result" - if [[ "$err" != "1" ]] - then - err=2 - if [[ "$result" =~ "FP_ARITH" || "$result" =~ "AMX" ]] - then - echo "Skip, not fail, for FP issues" - elif [[ "$result" =~ "PMM" ]] - then - echo "Skip, not fail, for Optane memory issues" - else - err=1 - fi - fi + err=1 done exit "$err"
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 352/1376 perf test stat_all_metrics: Ensure missing events fail test
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 08d9e883481b2c38326ed37314b1f6a1284c03d8 ]
Issue reported by Thomas Falcon and diagnosed by Kan Liang here:
https://lore.kernel.org/lkml/[email protected]/
Metrics with missing events can be erroneously skipped if they contain FP, AMX or PMM events.
Stable-dep-of: 8953bfd8820b ("perf tests: Skip metrics validation if system-wide recording lacks permission")
--- tools/perf/tests/shell/stat_all_metrics.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
tools/perf/tests/shell/stat_all_metrics.sh +7 -1
@@ -20,7 +20,13 @@ for m in $(perf list --raw-dump metrics); do result_err=$? if [[ $result_err -gt 0 ]] then - if [[ "$result" =~ \ + if [[ "$result" =~ "Cannot resolve IDs for" ]] + then + echo "Metric contains missing events" + echo $result + err=1 # Fail + continue + elif [[ "$result" =~ \ "Access to performance monitoring and observability operations is limited" ]] then echo "Permission failure"
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 353/1376 perf tests metrics: Permission related fixes
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 365e02ddb65d443f1ba16af5a4ddcd638f1e7823 ]
When permissions are limited running sleep without system wide isn't a good benchmark to run to achieve samples, switch to running noploop.
Remove indent for non-success cases.
Allow skip for the not counted case.
Minor debug changes.
Stable-dep-of: 8953bfd8820b ("perf tests: Skip metrics validation if system-wide recording lacks permission")
--- tools/perf/tests/shell/stat_all_metrics.sh | 118 +++++++++++---------- 1 file changed, 64 insertions(+), 54 deletions(-)
tools/perf/tests/shell/stat_all_metrics.sh +64 -54
@@ -7,86 +7,96 @@ ParanoidAndNotRoot() [ "$(id -u)" != 0 ] && [ "$(cat /proc/sys/kernel/perf_event_paranoid)" -gt $1 ] } +test_prog="sleep 0.01" system_wide_flag="-a" if ParanoidAndNotRoot 0 then system_wide_flag="" + test_prog="perf test -w noploop" fi err=0 for m in $(perf list --raw-dump metrics); do echo "Testing $m" - result=$(perf stat -M "$m" $system_wide_flag -- sleep 0.01 2>&1) + result=$(perf stat -M "$m" $system_wide_flag -- $test_prog 2>&1) result_err=$? - if [[ $result_err -gt 0 ]] + if [[ $result_err -eq 0 && "$result" =~ ${m:0:50} ]] then - if [[ "$result" =~ "Cannot resolve IDs for" ]] - then - echo "Metric contains missing events" - echo $result - err=1 # Fail - continue - elif [[ "$result" =~ \ - "Access to performance monitoring and observability operations is limited" ]] + # No error result and metric shown. + continue + fi + if [[ "$result" =~ "Cannot resolve IDs for" ]] + then + echo "Metric contains missing events" + echo $result + err=1 # Fail + continue + elif [[ "$result" =~ \ + "Access to performance monitoring and observability operations is limited" ]] + then + echo "Permission failure" + echo $result + if [[ $err -eq 0 ]] then - echo "Permission failure" - echo $result - if [[ $err -eq 0 ]] - then - err=2 # Skip - fi - continue - elif [[ "$result" =~ "in per-thread mode, enable system wide" ]] + err=2 # Skip + fi + continue + elif [[ "$result" =~ "in per-thread mode, enable system wide" ]] + then + echo "Permissions - need system wide mode" + echo $result + if [[ $err -eq 0 ]] then - echo "Permissions - need system wide mode" - echo $result - if [[ $err -eq 0 ]] - then - err=2 # Skip - fi - continue - elif [[ "$result" =~ "<not supported>" ]] + err=2 # Skip + fi + continue + elif [[ "$result" =~ "<not supported>" ]] + then + echo "Not supported events" + echo $result + if [[ $err -eq 0 ]] then - echo "Not supported events" - echo $result - if [[ $err -eq 0 ]] - then - err=2 # Skip - fi - continue - elif [[ "$result" =~ "FP_ARITH" || "$result" =~ "AMX" ]] + err=2 # Skip + fi + continue + elif [[ "$result" =~ "<not counted>" ]] + then + echo "Not counted events" + echo $result + if [[ $err -eq 0 ]] then - echo "FP issues" - echo $result - if [[ $err -eq 0 ]] - then - err=2 # Skip - fi - continue - elif [[ "$result" =~ "PMM" ]] + err=2 # Skip + fi + continue + elif [[ "$result" =~ "FP_ARITH" || "$result" =~ "AMX" ]] + then + echo "FP issues" + echo $result + if [[ $err -eq 0 ]] then - echo "Optane memory issues" - echo $result - if [[ $err -eq 0 ]] - then - err=2 # Skip - fi - continue + err=2 # Skip fi - fi - - if [[ "$result" =~ ${m:0:50} ]] + continue + elif [[ "$result" =~ "PMM" ]] then + echo "Optane memory issues" + echo $result + if [[ $err -eq 0 ]] + then + err=2 # Skip + fi continue fi # Failed, possibly the workload was too small so retry with something longer. result=$(perf stat -M "$m" $system_wide_flag -- perf bench internals synthesize 2>&1) - if [[ "$result" =~ ${m:0:50} ]] + result_err=$? + if [[ $result_err -eq 0 && "$result" =~ ${m:0:50} ]] then + # No error result and metric shown. continue fi - echo "Metric '$m' not printed in:" + echo "Metric '$m' has non-zero error '$result_err' or not printed in:" echo "$result" err=1 done
Signature · 1 line
2.53.0
Re: [PATCH 6.12 0353/1376] perf tests metrics: Permission related fixes
Hi Greg/Sasha,
Quoted 30 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit
365e02ddb65d443f1ba16af5a4ddcd638f1e7823]When permissions are limited running sleep without system wide isn't a good benchmark to run to achieve samples, switch to running noploop.
Remove indent for non-success cases.
Allow skip for the not counted case.
Minor debug changes.
Signed-off-by Ian Rogers <[email protected]>Cc Adrian Hunter <[email protected]>Cc Alexander Shishkin <[email protected]>Cc Ingo Molnar <[email protected]>Cc James Clark <[email protected]>Cc Jiri Olsa <[email protected]>Cc Kan Liang <[email protected]>Cc Mark Rutland <[email protected]>Cc Namhyung Kim <[email protected]>Cc Peter Zijlstra <[email protected]>Cc Weilin Wang <[email protected]>Signed-off-by Arnaldo Carvalho de Melo <[email protected]>
Quoted 6 lines
Stable-dep-of:
8953bfd8820b("perf tests: Skip metrics validation if system-wide recording lacks permission")Signed-off-by Sasha Levin <[email protected]>--- tools/perf/tests/shell/stat_all_metrics.sh | 118 +++++++++++---------- 1 file changed, 64 insertions(+), 54 deletions(-)
Hi Greg/Sasha,
I ran an AI-assisted backport review, and I have verified the report. It looks valid to me.
The test now uses a per-thread workload when system-wide perf access is restricted. Its skip logic relies on the EOPNOTSUPP per-thread diagnostic added immediately beforehand upstream. The 6.12 evsel__open_strerror() falls through to the generic error instead, so an unsupported per-thread PMU can be reported as a test failure.
Upstream prerequisite code:
if (!target__has_cpu(target))
return scnprintf(msg, size,
"Unsupported event (%s) in per-thread mode," " enable system wide with '-a'.", evsel__name(evsel));
Downstream 6.12.y test code:
elif [[ "$result" =~
"in per-thread mode, enable system wide" ]]
I think 6.12.y misses f0869f31562bde, "perf evsel: Add per-thread warning for EOPNOTSUPP open failues". Thoughts ?
thanks,
Harshit
Re: [PATCH 6.12 0353/1376] perf tests metrics: Permission related fixes
Quoted 2 lines
I think 6.12.y misses
f0869f31562bde, "perf evsel: Add per-thread warning for EOPNOTSUPP open failues". Thoughts ?
Queued for 6.12 and 6.6, thanks.
Signature · 2 lines
Thanks, Sasha
Greg Kroah-Hartman
maintainerPATCH 354/1376 perf test metrics: Update all metrics for possibly failing default metrics
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 91c1949d768520d9befa7761eb97c3826997da25 ]
Default metrics may use unsupported events and be ignored. These metrics shouldn't cause metric testing to fail.
Stable-dep-of: 8953bfd8820b ("perf tests: Skip metrics validation if system-wide recording lacks permission")
--- tools/perf/tests/shell/stat_all_metrics.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
tools/perf/tests/shell/stat_all_metrics.sh +6 -1
@@ -25,8 +25,13 @@ for m in $(perf list --raw-dump metrics); do # No error result and metric shown. continue fi - if [[ "$result" =~ "Cannot resolve IDs for" ]] + if [[ "$result" =~ "Cannot resolve IDs for" || "$result" =~ "No supported events found" ]] then + if [[ "$m" == @(l1_prefetch_miss_rate|stalled_cycles_per_instruction) ]] + then + # Default metrics that may use unsupported events. + continue + fi echo "Metric contains missing events" echo $result err=1 # Fail
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 355/1376 perf test all metrics: Fully ignore Default metric failures
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 41b67ab3d2f5be9d0b6e5ba9cbec97c820fc50e8 ]
Determine if a metric is default from perf list --raw-dump $m eg:
``` $ perf list --raw-dump l1_prefetch_miss_rate Default4 l1_prefetch_miss_rate ```
If a metric has "not supported" or "no supported events" then ignore these failures for default metrics. Tidy up the skip/fail messages in the output to make them easier to spot/read.
``` $ perf list -vv "all metrics" ... Testing llc_miss_rate [Ignored llc_miss_rate] failed but as a Default metric this can be expected Error: No supported events found. The LLC-loads event is not supported. ... ```
Stable-dep-of: 8953bfd8820b ("perf tests: Skip metrics validation if system-wide recording lacks permission")
--- tools/perf/tests/shell/stat_all_metrics.sh | 27 ++++++++++++++-------- 1 file changed, 17 insertions(+), 10 deletions(-)
tools/perf/tests/shell/stat_all_metrics.sh +17 -10
@@ -27,19 +27,20 @@ for m in $(perf list --raw-dump metrics); do fi if [[ "$result" =~ "Cannot resolve IDs for" || "$result" =~ "No supported events found" ]] then - if [[ "$m" == @(l1_prefetch_miss_rate|stalled_cycles_per_instruction) ]] + if [[ $(perf list --raw-dump $m) == "Default"* ]] then - # Default metrics that may use unsupported events. + echo "[Ignored $m] failed but as a Default metric this can be expected" + echo $result continue fi - echo "Metric contains missing events" + echo "[Failed $m] Metric contains missing events" echo $result err=1 # Fail continue elif [[ "$result" =~ \ "Access to performance monitoring and observability operations is limited" ]] then - echo "Permission failure" + echo "[Skipped $m] Permission failure" echo $result if [[ $err -eq 0 ]] then
@@ -48,7 +49,7 @@ for m in $(perf list --raw-dump metrics); do continue elif [[ "$result" =~ "in per-thread mode, enable system wide" ]] then - echo "Permissions - need system wide mode" + echo "[Skipped $m] Permissions - need system wide mode" echo $result if [[ $err -eq 0 ]] then
@@ -57,7 +58,13 @@ for m in $(perf list --raw-dump metrics); do continue elif [[ "$result" =~ "<not supported>" ]] then - echo "Not supported events" + if [[ $(perf list --raw-dump $m) == "Default"* ]] + then + echo "[Ignored $m] failed but as a Default metric this can be expected" + echo $result + continue + fi + echo "[Skipped $m] Not supported events" echo $result if [[ $err -eq 0 ]] then
@@ -66,7 +73,7 @@ for m in $(perf list --raw-dump metrics); do continue elif [[ "$result" =~ "<not counted>" ]] then - echo "Not counted events" + echo "[Skipped $m] Not counted events" echo $result if [[ $err -eq 0 ]] then
@@ -75,7 +82,7 @@ for m in $(perf list --raw-dump metrics); do continue elif [[ "$result" =~ "FP_ARITH" || "$result" =~ "AMX" ]] then - echo "FP issues" + echo "[Skipped $m] FP issues" echo $result if [[ $err -eq 0 ]] then
@@ -84,7 +91,7 @@ for m in $(perf list --raw-dump metrics); do continue elif [[ "$result" =~ "PMM" ]] then - echo "Optane memory issues" + echo "[Skipped $m] Optane memory issues" echo $result if [[ $err -eq 0 ]] then
@@ -101,7 +108,7 @@ for m in $(perf list --raw-dump metrics); do # No error result and metric shown. continue fi - echo "Metric '$m' has non-zero error '$result_err' or not printed in:" + echo "[Failed $m] has non-zero error '$result_err' or not printed in:" echo "$result" err=1 done
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 356/1376 perf test: Do not skip when some metrics tests succeeded
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namhyung Kim <[email protected]>
[ Upstream commit 1c89bc1b95fa9058f3e7cd37f1142939261417d5 ]
I think the return value of SKIP (2) should be used when it skipped the entire test suite rather than a few of them. While the FAIL should be reserved if any of test failed.
$ perf test -vv 110 110: perf all metrics test: --- start --- test child forked, pid 2496399 Testing tma_core_bound Testing tma_info_core_ilp Testing tma_info_memory_l2mpki Testing tma_memory_bound Testing tma_bottleneck_irregular_overhead Testing tma_bottleneck_mispredictions Testing tma_info_bad_spec_branch_misprediction_cost Testing tma_info_bad_spec_ipmisp_cond_ntaken Testing tma_info_bad_spec_ipmisp_cond_taken Testing tma_info_bad_spec_ipmisp_indirect Testing tma_info_bad_spec_ipmisp_ret Testing tma_info_bad_spec_ipmispredict Testing tma_info_branches_callret Testing tma_info_branches_cond_nt Testing tma_info_branches_cond_tk Testing tma_info_branches_jump Testing tma_info_branches_other_branches Testing tma_branch_mispredicts Testing tma_clears_resteers Testing tma_machine_clears Testing tma_mispredicts_resteers Testing tma_bottleneck_big_code Testing tma_icache_misses Testing tma_itlb_misses Testing tma_unknown_branches Testing tma_info_bad_spec_spec_clears_ratio Testing tma_other_mispredicts Testing tma_branch_instructions Testing tma_info_frontend_tbpc Testing tma_info_inst_mix_bptkbranch Testing tma_info_inst_mix_ipbranch Testing tma_info_inst_mix_ipcall Testing tma_info_inst_mix_iptb Testing tma_info_system_ipfarbranch Testing tma_info_thread_uptb Testing tma_bottleneck_branching_overhead Testing tma_nop_instructions Testing tma_bottleneck_compute_bound_est Testing tma_divider Testing tma_ports_utilized_3m Testing tma_bottleneck_instruction_fetch_bw Testing tma_frontend_bound Testing tma_assists Testing tma_other_nukes Testing tma_serializing_operation Testing tma_bottleneck_data_cache_memory_bandwidth Testing tma_fb_full Testing tma_mem_bandwidth Testing tma_sq_full Testing tma_bottleneck_data_cache_memory_latency Testing tma_l1_latency_dependency Testing tma_l2_bound Testing tma_l3_hit_latency Testing tma_mem_latency Testing tma_store_latency Testing tma_bottleneck_memory_synchronization Testing tma_contested_accesses Testing tma_data_sharing Testing tma_false_sharing Testing tma_bottleneck_memory_data_tlbs Testing tma_dtlb_load Testing tma_dtlb_store Testing tma_backend_bound Testing tma_bottleneck_other_bottlenecks Testing tma_bottleneck_useful_work Testing tma_retiring Testing tma_info_memory_fb_hpki Testing tma_info_memory_l1mpki Testing tma_info_memory_l1mpki_load Testing tma_info_memory_l2hpki_all Testing tma_info_memory_l2hpki_load Testing tma_info_memory_l2mpki_all Testing tma_info_memory_l2mpki_load Testing tma_l1_bound Testing tma_l3_bound Testing tma_info_memory_l2mpki_rfo Testing tma_fp_scalar Testing tma_fp_vector Testing tma_fp_vector_128b Testing tma_fp_vector_256b Testing tma_fp_vector_512b Testing tma_port_0 Testing tma_x87_use Testing tma_info_botlnk_l0_core_bound_likely Testing tma_info_core_fp_arith_utilization Testing tma_info_pipeline_execute Testing tma_info_system_gflops Testing tma_info_thread_execute_per_issue Testing tma_dsb Testing tma_info_botlnk_l2_dsb_bandwidth Testing tma_info_frontend_dsb_coverage Testing tma_decoder0_alone Testing tma_dsb_switches Testing tma_info_botlnk_l2_dsb_misses Testing tma_info_frontend_dsb_switch_cost Testing tma_info_frontend_ipdsb_miss_ret Testing tma_mite Testing tma_mite_4wide Testing CPUs_utilized Testing backend_cycles_idle [Ignored backend_cycles_idle] failed but as a Default metric this can be expected Performance counter stats for 'perf test -w noploop': <not counted> cpu-cycles:u <not supported> stalled-cycles-backend:u 1.014051473 seconds time elapsed 1.005718000 seconds user 0.008013000 seconds sys Testing branch_frequency Testing branch_miss_rate Testing cs_per_second Testing cycles_frequency Testing frontend_cycles_idle [Ignored frontend_cycles_idle] failed but as a Default metric this can be expected Performance counter stats for 'perf test -w noploop': <not counted> cpu-cycles:u <not supported> stalled-cycles-frontend:u 1.012813656 seconds time elapsed 1.004603000 seconds user 0.008004000 seconds sys Testing insn_per_cycle Testing migrations_per_second Testing page_faults_per_second Testing stalled_cycles_per_instruction [Ignored stalled_cycles_per_instruction] failed but as a Default metric this can be expected Error: No supported events found. The stalled-cycles-backend:u event is not supported. Testing tma_bad_speculation Testing l1d_miss_rate Testing llc_miss_rate Testing dtlb_miss_rate Testing itlb_miss_rate [Ignored itlb_miss_rate] failed but as a Default metric this can be expected Performance counter stats for 'perf test -w noploop': <not supported> iTLB-loads:u 3,097 iTLB-load-misses:u 1.012766732 seconds time elapsed 1.004318000 seconds user 0.008002000 seconds sys Testing l1i_miss_rate [Ignored l1i_miss_rate] failed but as a Default metric this can be expected Performance counter stats for 'perf test -w noploop': <not counted> L1-icache-load-misses:u <not supported> L1-icache-loads:u 1.013606395 seconds time elapsed 1.001371000 seconds user 0.011968000 seconds sys Testing l1_prefetch_miss_rate [Ignored l1_prefetch_miss_rate] failed but as a Default metric this can be expected Error: No supported events found. The L1-dcache-prefetches:u event is not supported. Testing tma_info_botlnk_l2_ic_misses Testing tma_info_frontend_fetch_upc Testing tma_info_frontend_icache_miss_latency Testing tma_info_frontend_ipunknown_branch Testing tma_info_frontend_lsd_coverage Testing tma_info_memory_tlb_code_stlb_mpki Testing tma_info_pipeline_fetch_dsb Testing tma_info_pipeline_fetch_lsd Testing tma_info_pipeline_fetch_mite Testing tma_info_pipeline_fetch_ms Testing tma_fetch_bandwidth Testing tma_lsd Testing tma_branch_resteers Testing tma_code_l2_hit Testing tma_code_l2_miss Testing tma_code_stlb_hit Testing tma_code_stlb_miss Testing tma_code_stlb_miss_2m Testing tma_code_stlb_miss_4k Testing tma_lcp Testing tma_ms_switches Testing tma_info_core_flopc Testing tma_info_inst_mix_iparith Testing tma_info_inst_mix_iparith_avx128 Testing tma_info_inst_mix_iparith_avx256 Testing tma_info_inst_mix_iparith_avx512 Testing tma_info_inst_mix_iparith_scalar_dp Testing tma_info_inst_mix_iparith_scalar_sp Testing tma_info_inst_mix_ipflop Testing tma_info_inst_mix_ippause Testing tma_fetch_latency Testing tma_fp_arith Testing tma_fp_assists Testing tma_info_system_cpu_utilization Testing tma_info_system_dram_bw_use [Skipped tma_info_system_dram_bw_use] Not supported events Performance counter stats for 'perf test -w noploop': <not supported> UNC_ARB_TRK_REQUESTS.ALL:u <not supported> UNC_ARB_COH_TRK_REQUESTS.ALL:u 1,013,554,749 duration_time 1.013527265 seconds time elapsed 1.005417000 seconds user 0.008011000 seconds sys Testing tma_info_frontend_l2mpki_code Testing tma_info_frontend_l2mpki_code_all Testing tma_info_inst_mix_ipload Testing tma_info_inst_mix_ipstore Testing tma_info_memory_latency_load_l2_miss_latency Testing tma_lock_latency Testing tma_info_memory_core_l1d_cache_fill_bw_2t Testing tma_info_memory_core_l2_cache_fill_bw_2t Testing tma_info_memory_core_l3_cache_access_bw_2t Testing tma_info_memory_core_l3_cache_fill_bw_2t Testing tma_info_memory_l1d_cache_fill_bw Testing tma_info_memory_l2_cache_fill_bw Testing tma_info_memory_l3_cache_access_bw Testing tma_info_memory_l3_cache_fill_bw Testing tma_info_memory_l3mpki Testing tma_info_memory_load_miss_real_latency Testing tma_info_memory_mix_bus_lock_pki Testing tma_info_memory_mix_uc_load_pki Testing tma_info_memory_mlp Testing tma_info_memory_tlb_load_stlb_mpki Testing tma_info_memory_tlb_page_walks_utilization Testing tma_info_memory_tlb_store_stlb_mpki Testing tma_info_system_mem_parallel_reads [Skipped tma_info_system_mem_parallel_reads] Not supported events Performance counter stats for 'perf test -w noploop': <not supported> UNC_ARB_DAT_OCCUPANCY.RD:u <not counted> UNC_ARB_DAT_OCCUPANCY.RD/cmask=1/ 1.013354884 seconds time elapsed 1.009239000 seconds user 0.004004000 seconds sys Testing tma_info_system_mem_read_latency [Skipped tma_info_system_mem_read_latency] Not supported events Performance counter stats for 'perf test -w noploop': <not supported> UNC_ARB_DAT_OCCUPANCY.RD:u <not counted> UNC_ARB_TRK_OCCUPANCY.RD <not counted> UNC_ARB_TRK_REQUESTS.RD 1.012882143 seconds time elapsed 1.004600000 seconds user 0.008036000 seconds sys Testing tma_info_thread_cpi Testing tma_streaming_stores Testing tma_dram_bound Testing tma_store_bound Testing tma_l2_hit_latency Testing tma_load_stlb_hit Testing tma_load_stlb_miss Testing tma_load_stlb_miss_1g Testing tma_load_stlb_miss_2m Testing tma_load_stlb_miss_4k Testing tma_store_stlb_hit Testing tma_store_stlb_miss Testing tma_store_stlb_miss_1g Testing tma_store_stlb_miss_2m Testing tma_store_stlb_miss_4k Testing tma_info_memory_latency_data_l2_mlp Testing tma_info_memory_latency_load_l2_mlp Testing tma_info_pipeline_ipassist Testing tma_microcode_sequencer Testing tma_ms Testing tma_info_system_kernel_cpi [Failed tma_info_system_kernel_cpi] Metric contains missing events Error: No supported events found. Access to performance monitoring and observability operations is limited. Consider adjusting /proc/sys/kernel/perf_event_paranoid setting to open access to performance monitoring and observability operations for processes without CAP_PERFMON, CAP_SYS_PTRACE or CAP_SYS_ADMIN Linux capability. More information can be found at 'Perf events and tool security' document: https://www.kernel.org/doc/html/latest/admin-guide/perf-security.html perf_event_paranoid setting is 2: -1: Allow use of (almost) all events by all users Ignore mlock limit after perf_event_mlock_kb without CAP_IPC_LOCK >= 0: Disallow raw and ftrace function tracepoint access >= 1: Disallow CPU event access >= 2: Disallow kernel profiling To make the adjusted perf_event_paranoid setting permanent preserve it in /etc/sysctl.conf (e.g. kernel.perf_event_paranoid = <setting>) Testing tma_info_system_kernel_utilization [Failed tma_info_system_kernel_utilization] Metric contains missing events Error: No supported events found. Access to performance monitoring and observability operations is limited. Consider adjusting /proc/sys/kernel/perf_event_paranoid setting to open access to performance monitoring and observability operations for processes without CAP_PERFMON, CAP_SYS_PTRACE or CAP_SYS_ADMIN Linux capability. More information can be found at 'Perf events and tool security' document: https://www.kernel.org/doc/html/latest/admin-guide/perf-security.html perf_event_paranoid setting is 2: -1: Allow use of (almost) all events by all users Ignore mlock limit after perf_event_mlock_kb without CAP_IPC_LOCK >= 0: Disallow raw and ftrace function tracepoint access >= 1: Disallow CPU event access >= 2: Disallow kernel profiling To make the adjusted perf_event_paranoid setting permanent preserve it in /etc/sysctl.conf (e.g. kernel.perf_event_paranoid = <setting>) Testing tma_info_pipeline_retire Testing tma_info_thread_clks Testing tma_info_thread_uoppi Testing tma_memory_operations Testing tma_other_light_ops Testing tma_ports_utilization Testing tma_ports_utilized_0 Testing tma_ports_utilized_1 Testing tma_ports_utilized_2 Testing C10_Pkg_Residency [Failed C10_Pkg_Residency] Metric contains missing events WARNING: grouped events cpus do not match. Events with CPUs not matching the leader will be removed from the group. anon group { cstate_pkg/c10-residency/, msr/tsc/ } Error: No supported events found. Invalid event (cstate_pkg/c10-residency/u) in per-thread mode, enable system wide with '-a'. Testing C2_Pkg_Residency [Failed C2_Pkg_Residency] Metric contains missing events WARNING: grouped events cpus do not match. Events with CPUs not matching the leader will be removed from the group. anon group { cstate_pkg/c2-residency/, msr/tsc/ } Error: No supported events found. Invalid event (cstate_pkg/c2-residency/u) in per-thread mode, enable system wide with '-a'. Testing C3_Pkg_Residency [Failed C3_Pkg_Residency] Metric contains missing events WARNING: grouped events cpus do not match. Events with CPUs not matching the leader will be removed from the group. anon group { msr/tsc/, cstate_pkg/c3-residency/ } Error: No supported events found. Invalid event (msr/tsc/u) in per-thread mode, enable system wide with '-a'. Testing C6_Core_Residency [Failed C6_Core_Residency] Metric contains missing events WARNING: grouped events cpus do not match. Events with CPUs not matching the leader will be removed from the group. anon group { cstate_core/c6-residency/, msr/tsc/ } Error: No supported events found. Invalid event (cstate_core/c6-residency/u) in per-thread mode, enable system wide with '-a'. Testing C6_Pkg_Residency [Failed C6_Pkg_Residency] Metric contains missing events WARNING: grouped events cpus do not match. Events with CPUs not matching the leader will be removed from the group. anon group { cstate_pkg/c6-residency/, msr/tsc/ } Error: No supported events found. Invalid event (cstate_pkg/c6-residency/u) in per-thread mode, enable system wide with '-a'. Testing C7_Core_Residency [Failed C7_Core_Residency] Metric contains missing events WARNING: grouped events cpus do not match. Events with CPUs not matching the leader will be removed from the group. anon group { cstate_core/c7-residency/, msr/tsc/ } Error: No supported events found. Invalid event (cstate_core/c7-residency/u) in per-thread mode, enable system wide with '-a'. Testing C7_Pkg_Residency [Failed C7_Pkg_Residency] Metric contains missing events WARNING: grouped events cpus do not match. Events with CPUs not matching the leader will be removed from the group. anon group { cstate_pkg/c7-residency/, msr/tsc/ } Error: No supported events found. Invalid event (cstate_pkg/c7-residency/u) in per-thread mode, enable system wide with '-a'. Testing C8_Pkg_Residency [Failed C8_Pkg_Residency] Metric contains missing events WARNING: grouped events cpus do not match. Events with CPUs not matching the leader will be removed from the group. anon group { cstate_pkg/c8-residency/, msr/tsc/ } Error: No supported events found. Invalid event (cstate_pkg/c8-residency/u) in per-thread mode, enable system wide with '-a'. Testing C9_Pkg_Residency [Failed C9_Pkg_Residency] Metric contains missing events WARNING: grouped events cpus do not match. Events with CPUs not matching the leader will be removed from the group. anon group { cstate_pkg/c9-residency/, msr/tsc/ } Error: No supported events found. Invalid event (cstate_pkg/c9-residency/u) in per-thread mode, enable system wide with '-a'. Testing tma_info_core_epc Testing tma_info_system_core_frequency Testing tma_info_system_power [Skipped tma_info_system_power] Not supported events Performance counter stats for 'perf test -w noploop': <not supported> Joules power/energy-pkg/u 1,013,238,256 duration_time 1.013223072 seconds time elapsed 0.995924000 seconds user 0.011903000 seconds sys Testing tma_info_system_power_license0_utilization Testing tma_info_system_power_license1_utilization Testing tma_info_system_power_license2_utilization Testing tma_info_system_turbo_utilization Testing tma_info_inst_mix_ipswpf Testing tma_info_memory_prefetches_useless_hwpf Testing tma_info_core_coreipc Testing tma_info_thread_ipc Testing tma_heavy_operations Testing tma_light_operations Testing tma_info_core_core_clks Testing tma_info_system_smt_2t_utilization Testing tma_info_thread_slots_utilization Testing UNCORE_FREQ [Skipped UNCORE_FREQ] Not supported events Performance counter stats for 'perf test -w noploop': <not supported> UNC_CLOCK.SOCKET:u 1,015,993,466 duration_time 1.015949387 seconds time elapsed 1.007676000 seconds user 0.008029000 seconds sys Testing tma_info_system_socket_clks [Failed tma_info_system_socket_clks] Metric contains missing events Error: No supported events found. Invalid event (UNC_CLOCK.SOCKET:u) in per-thread mode, enable system wide with '-a'. Testing tma_info_inst_mix_instructions Testing tma_info_system_cpus_utilized Testing tma_info_system_mux Testing tma_info_system_time Testing tma_info_thread_slots Testing tma_few_uops_instructions Testing tma_4k_aliasing Testing tma_cisc Testing tma_fp_divider Testing tma_int_divider Testing tma_slow_pause Testing tma_split_loads Testing tma_split_stores Testing tma_store_fwd_blk Testing tma_alu_op_utilization Testing tma_load_op_utilization Testing tma_mixing_vectors Testing tma_store_op_utilization Testing tma_port_1 Testing tma_port_5 Testing tma_port_6 Testing smi_cycles [Skipped smi_cycles] Not supported events Performance counter stats for 'perf test -w noploop': <not supported> msr/smi/u <not supported> msr/aperf/u 3,965,789,327 cycles:u 1.012779591 seconds time elapsed 1.004579000 seconds user 0.007972000 seconds sys Testing smi_num [Failed smi_num] Metric contains missing events Error: No supported events found. Invalid event (msr/smi/u) in per-thread mode, enable system wide with '-a'. Testing tsx_aborted_cycles Testing tsx_cycles_per_elision Testing tsx_cycles_per_transaction Testing tsx_transactional_cycles ---- end(-1) ---- 110: perf all metrics test : FAILED!
Stable-dep-of: 8953bfd8820b ("perf tests: Skip metrics validation if system-wide recording lacks permission")
--- tools/perf/tests/shell/stat_all_metrics.sh | 29 ++++++++++++++++------ 1 file changed, 22 insertions(+), 7 deletions(-)
tools/perf/tests/shell/stat_all_metrics.sh +22 -7
@@ -15,7 +15,8 @@ then test_prog="perf test -w noploop" fi -err=0 +skip=0 +err=3 for m in $(perf list --raw-dump metrics); do echo "Testing $m" result=$(perf stat -M "$m" $system_wide_flag -- $test_prog 2>&1)
@@ -23,6 +24,10 @@ for m in $(perf list --raw-dump metrics); do if [[ $result_err -eq 0 && "$result" =~ ${m:0:50} ]] then # No error result and metric shown. + if [[ "$err" -ne 1 ]] + then + err=0 + fi continue fi if [[ "$result" =~ "Cannot resolve IDs for" || "$result" =~ "No supported events found" ]]
@@ -44,7 +49,7 @@ for m in $(perf list --raw-dump metrics); do echo $result if [[ $err -eq 0 ]] then - err=2 # Skip + skip=1 fi continue elif [[ "$result" =~ "in per-thread mode, enable system wide" ]]
@@ -53,7 +58,7 @@ for m in $(perf list --raw-dump metrics); do echo $result if [[ $err -eq 0 ]] then - err=2 # Skip + skip=1 fi continue elif [[ "$result" =~ "<not supported>" ]]
@@ -68,7 +73,7 @@ for m in $(perf list --raw-dump metrics); do echo $result if [[ $err -eq 0 ]] then - err=2 # Skip + skip=1 fi continue elif [[ "$result" =~ "<not counted>" ]]
@@ -77,7 +82,7 @@ for m in $(perf list --raw-dump metrics); do echo $result if [[ $err -eq 0 ]] then - err=2 # Skip + skip=1 fi continue elif [[ "$result" =~ "FP_ARITH" || "$result" =~ "AMX" ]]
@@ -86,7 +91,7 @@ for m in $(perf list --raw-dump metrics); do echo $result if [[ $err -eq 0 ]] then - err=2 # Skip + skip=1 fi continue elif [[ "$result" =~ "PMM" ]]
@@ -95,7 +100,7 @@ for m in $(perf list --raw-dump metrics); do echo $result if [[ $err -eq 0 ]] then - err=2 # Skip + skip=1 fi continue fi
@@ -106,6 +111,10 @@ for m in $(perf list --raw-dump metrics); do if [[ $result_err -eq 0 && "$result" =~ ${m:0:50} ]] then # No error result and metric shown. + if [[ "$err" -ne 1 ]] + then + err=0 + fi continue fi echo "[Failed $m] has non-zero error '$result_err' or not printed in:"
@@ -113,4 +122,10 @@ for m in $(perf list --raw-dump metrics); do err=1 done +# return SKIP only if no success returned +if [[ "$err" -eq 3 && "$skip" -eq 1 ]] +then + err=2 +fi + exit "$err"
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 357/1376 perf tests: Skip metrics validation if system-wide recording lacks permission
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 8953bfd8820b6525032023fda3a420098c1823ae ]
The metrics value validation test requires system-wide recording (-a), which can fail on systems without root permissions or where paranoid levels restrict tracing. Add a check to skip the test if -a is not supported.
Also fix false negatives during validation by updating parse error string patterns and resolving issues in metric list generation.
--- .../tests/shell/lib/perf_metric_validation.py | 11 ++- tools/perf/tests/shell/stat_all_metrics.sh | 75 ++++++++++++------- tools/perf/tests/shell/stat_metrics_values.sh | 7 ++ 3 files changed, 60 insertions(+), 33 deletions(-)
tools/perf/tests/shell/lib/perf_metric_validation.py +7 -4
@@ -381,10 +381,13 @@ class Validator: wl = workload.split() command.extend(wl) print(" ".join(command)) - cmd = subprocess.run(command, stderr=subprocess.PIPE, encoding='utf-8') - data = [x+'}' for x in cmd.stderr.split('}\n') if x] - if data[0][0] != '{': - data[0] = data[0][data[0].find('{'):] + cmd = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='utf-8') + lines = cmd.stderr.splitlines() + cmd.stdout.splitlines() + data = [] + for line in lines: + line = line.strip() + if line.startswith('{') and line.endswith('}'): + data.append(line) return data def collect_perf(self, workload: str):
tools/perf/tests/shell/stat_all_metrics.sh +46 -29
110 lines not on this page · raw message
tools/perf/tests/shell/stat_metrics_values.sh +7 -0
@@ -8,6 +8,13 @@ shelldir=$(dirname "$0") grep -q GenuineIntel /proc/cpuinfo || { echo Skipping non-Intel; exit 2; } +# Skip if no permission to record system-wide events +if ! perf stat -a -e instructions sleep 0.01 >/dev/null 2>&1; then + echo "Skipping: no permission to record system-wide events (-a)" + exit 2 +fi + + pythonvalidator=$(dirname $0)/lib/perf_metric_validation.py rulefile=$(dirname $0)/lib/perf_metric_validation_rules.json tmpdir=$(mktemp -d /tmp/__perf_test.program.XXXXX)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 358/1376 perf test: Use sqrtloop workload to test bperf event
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tengda Wu <[email protected]>
[ Upstream commit d36e5b36a2928b30e09ff59ce5ce2d5df935176e ]
Replace brstack workload with sqrtloop workload, because sqrtloop workload contains fork(), which is suitable for testing the bperf event inheritance feature.
Stable-dep-of: b02027776ac5 ("perf tests: Fix flakiness in BPF counters test on hybrid systems")
--- tools/perf/tests/shell/stat_bpf_counters.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/tests/shell/stat_bpf_counters.sh +1 -1
@@ -4,7 +4,7 @@ set -e -workload="perf test -w brstack" +workload="perf test -w sqrtloop" # check whether $2 is within +/- 20% of $1 compare_number()
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 359/1376 perf test: Fix perf stat --bpf-counters on hybrid machines
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namhyung Kim <[email protected]>
[ Upstream commit d9db9c8db56c3e378aa5c91637664f77ca5a6f72 ]
The test constantly fails on my Intel hybrid machine. The issue was it has two events in the output even if I only gave it one event.
$ perf stat -e instructions -- perf test -w sqrtloop
Performance counter stats for 'perf test -w sqrtloop':
910,856,421 cpu_atom/instructions/ (28.05%)
14,852,865,997 cpu_core/instructions/ (96.79%) 1.014313341 seconds time elapsed
1.004114000 seconds user
0.008174000 seconds sysLet's modify the awk script to add the values for each line and print the total. The variable 'i' has a number of input lines that have valid output and variable 'c' has the sum of actual counter values. That way it should work on any platforms.
Stable-dep-of: b02027776ac5 ("perf tests: Fix flakiness in BPF counters test on hybrid systems")
--- tools/perf/tests/shell/stat_bpf_counters.sh | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-)
tools/perf/tests/shell/stat_bpf_counters.sh +16 -4
@@ -41,8 +41,14 @@ check_counts() test_bpf_counters() { printf "Testing --bpf-counters " - base_instructions=$(perf stat --no-big-num -e instructions -- $workload 2>&1 | awk '/instructions/ {print $1}') - bpf_instructions=$(perf stat --no-big-num --bpf-counters -e instructions -- $workload 2>&1 | awk '/instructions/ {print $1}') + base_instructions=$(perf stat --no-big-num -e instructions -- $workload 2>&1 | \ + awk -v i=0 -v c=0 '/instructions/ { \ + if ($1 != "<not") { i++; c += $1 } \ + } END { if (i > 0) printf "%.0f", c; else print "<not" }') + bpf_instructions=$(perf stat --no-big-num --bpf-counters -e instructions -- $workload 2>&1 | \ + awk -v i=0 -v c=0 '/instructions/ { \ + if ($1 != "<not") { i++; c += $1 } \ + } END { if (i > 0) printf "%.0f", c; else print "<not" }') check_counts $base_instructions $bpf_instructions compare_number $base_instructions $bpf_instructions echo "[Success]"
@@ -52,8 +58,14 @@ test_bpf_modifier() { printf "Testing bpf event modifier " stat_output=$(perf stat --no-big-num -e instructions/name=base_instructions/,instructions/name=bpf_instructions/b -- $workload 2>&1) - base_instructions=$(echo "$stat_output"| awk '/base_instructions/ {print $1}') - bpf_instructions=$(echo "$stat_output"| awk '/bpf_instructions/ {print $1}') + base_instructions=$(echo "$stat_output"| \ + awk -v i=0 -v c=0 '/base_instructions/ { \ + if ($1 != "<not") { i++; c += $1 } \ + } END { if (i > 0) printf "%.0f", c; else print "<not" }') + bpf_instructions=$(echo "$stat_output"| \ + awk -v i=0 -v c=0 '/bpf_instructions/ { \ + if ($1 != "<not") { i++; c += $1 } \ + } END { if (i > 0) printf "%.0f", c; else print "<not" }') check_counts $base_instructions $bpf_instructions compare_number $base_instructions $bpf_instructions echo "[Success]"
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 360/1376 perf tests: Fix flakiness in BPF counters test on hybrid systems
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit b02027776ac5bf737f1b76f3759f405e376097e5 ]
The perf stat --bpf-counters test fails intermittently on hybrid architectures or systems with dynamic frequency scaling (DVFS). This happens because the test workload (sqrtloop) runs for a fixed 1-second duration, and the CPU frequency can scale dynamically between idle and maximum frequency. As the first run runs on a cold CPU and the second run runs on a warmed-up CPU (or vice versa), the number of instructions executed in 1 second differs by up to 2.2x, violating the comparison tolerance.
Also, when running as root, BPF tracepoints and scheduling programs trigger frequently. Since standard perf stat -e instructions measures both user and kernel space instructions, it counts BPF helper and program execution overheads, whereas the BPF counters themselves do not self- measure. This introduces a large kernel-space instruction count discrepancy between standard and BPF counters.
Fix these issues by:
1. Switching the workload to a strictly deterministic, iteration-based
workload: awk 'BEGIN { for (i=0; i<10000000; i++) sum+=i }'. We pin
the
workload to a single random allowed CPU using taskset -c $CPU via a
bash array.
2. Restricting the counted event to user-space only (instructions:u or /u).
3. Tightening the comparison tolerance from 20% to 15%.
These modifications isolate the measurements to user-space instructions of the deterministic loop, which executes a virtually identical number of instructions on both runs (with less than 0.001% variation), eliminating Dynamic Frequency Scaling (DVFS), kernel scheduling noise, and BPF helper self-measurement overheads.
--- tools/perf/tests/shell/stat_bpf_counters.sh | 28 +++++++++++++-------- 1 file changed, 18 insertions(+), 10 deletions(-)
tools/perf/tests/shell/stat_bpf_counters.sh +18 -10
@@ -4,21 +4,26 @@ set -e -workload="perf test -w sqrtloop" +# Get the first allowed CPU +CPU=$(taskset -c -p $$ | awk -F': ' '{print $2}' | awk -F'[,-]' '{print $1}') +if [ -z "$CPU" ]; then + CPU=0 +fi +workload=(taskset -c "$CPU" awk 'BEGIN { for (i=0; i<10000000; i++) sum+=i }') -# check whether $2 is within +/- 20% of $1 +# check whether $2 is within +/- 15% of $1 compare_number() { first_num=$1 second_num=$2 - # upper bound is first_num * 120% - upper=$(expr $first_num + $first_num / 5 ) - # lower bound is first_num * 80% - lower=$(expr $first_num - $first_num / 5 ) + # upper bound is first_num * 115% + upper=$(expr $first_num + $first_num / 20 \* 3 ) + # lower bound is first_num * 85% + lower=$(expr $first_num - $first_num / 20 \* 3 ) if [ $second_num -gt $upper ] || [ $second_num -lt $lower ]; then - echo "The difference between $first_num and $second_num are greater than 20%." + echo "The difference between $first_num and $second_num are greater than 15%." exit 1 fi }
@@ -41,11 +46,12 @@ check_counts() test_bpf_counters() { printf "Testing --bpf-counters " - base_instructions=$(perf stat --no-big-num -e instructions -- $workload 2>&1 | \ + base_instructions=$(perf stat --no-big-num -e instructions:u -- "${workload[@]}" 2>&1 | \ awk -v i=0 -v c=0 '/instructions/ { \ if ($1 != "<not") { i++; c += $1 } \ } END { if (i > 0) printf "%.0f", c; else print "<not" }') - bpf_instructions=$(perf stat --no-big-num --bpf-counters -e instructions -- $workload 2>&1 | \ + bpf_instructions=$(perf stat --no-big-num --bpf-counters -e instructions:u \ + -- "${workload[@]}" 2>&1 | \ awk -v i=0 -v c=0 '/instructions/ { \ if ($1 != "<not") { i++; c += $1 } \ } END { if (i > 0) printf "%.0f", c; else print "<not" }')
@@ -57,7 +63,9 @@ test_bpf_counters() test_bpf_modifier() { printf "Testing bpf event modifier " - stat_output=$(perf stat --no-big-num -e instructions/name=base_instructions/,instructions/name=bpf_instructions/b -- $workload 2>&1) + stat_output=$(perf stat --no-big-num \ + -e instructions/name=base_instructions/u,instructions/name=bpf_instructions/bu \ + -- "${workload[@]}" 2>&1) base_instructions=$(echo "$stat_output"| \ awk -v i=0 -v c=0 '/base_instructions/ { \ if ($1 != "<not") { i++; c += $1 } \
Signature · 1 line
2.53.0
Re: [PATCH 6.12 0360/1376] perf tests: Fix flakiness in BPF counters test on hybrid systems
Hi Greg/Sasha,
Quoted 89 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit
b02027776ac5bf737f1b76f3759f405e376097e5]The
perf stat --bpf-counters testfails intermittently on hybrid architectures or systems with dynamic frequency scaling (DVFS). This happens because the test workload (sqrtloop) runs for a fixed 1-second duration, and the CPU frequency can scale dynamically between idle and maximum frequency. As the first run runs on a cold CPU and the second run runs on a warmed-up CPU (or vice versa), the number of instructions executed in 1 second differs by up to 2.2x, violating the comparison tolerance.Also, when running as root, BPF tracepoints and scheduling programs trigger frequently. Since standard
perf stat -e instructionsmeasures both user and kernel space instructions, it counts BPF helper and program execution overheads, whereas the BPF counters themselves do not self- measure. This introduces a large kernel-space instruction count discrepancy between standard and BPF counters.Fix these issues by:
1. Switching the workload to a strictly deterministic, iteration-basedworkload: `awk 'BEGIN { for (i=0; i<10000000; i++) sum+=i }'`. We pinthe
workload to a single random allowed CPU usingtaskset -c $CPUvia a
bash array.
2. Restricting the counted event to user-space only (instructions:uor/u).
3. Tightening the comparison tolerance from 20% to 15%.These modifications isolate the measurements to user-space instructions of the deterministic loop, which executes a virtually identical number of instructions on both runs (with less than 0.001% variation), eliminating Dynamic Frequency Scaling (DVFS), kernel scheduling noise, and BPF helper self-measurement overheads.
Fixes 2c0cb9f56020 ("perf test: Add a shell test for 'perf stat --bpf-counters' new option")Assisted-by Antigravity:gemini-3.1-proSigned-off-by Ian Rogers <[email protected]>Signed-off-by Namhyung Kim <[email protected]>Signed-off-by Sasha Levin <[email protected]>--- tools/perf/tests/shell/stat_bpf_counters.sh | 28 +++++++++++++-------- 1 file changed, 18 insertions(+), 10 deletions(-)tools/perf/tests/shell/stat_bpf_counters.sh +12
-7@@ -4,21 +4,26 @@ set -e -workload="perf test -w sqrtloop" +# Get the first allowed CPU +CPU=$(taskset -c -p $$ | awk -F': ' '{print $2}' | awk -F'[,-]' '{print $1}') +if [ -z "$CPU" ]; then + CPU=0 +fi +workload=(taskset -c "$CPU" awk 'BEGIN { for (i=0; i<10000000; i++) sum+=i }') -# check whether $2 is within +/- 20% of $1 +# check whether $2 is within +/- 15% of $1 compare_number() { first_num=$1 second_num=$2 - # upper bound is first_num * 120% - upper=$(expr $first_num + $first_num / 5 ) - # lower bound is first_num * 80% - lower=$(expr $first_num - $first_num / 5 ) + # upper bound is first_num * 115% + upper=$(expr $first_num + $first_num / 20 \* 3 ) + # lower bound is first_num * 85% + lower=$(expr $first_num - $first_num / 20 \* 3 ) if [ $second_num -gt $upper ] || [ $second_num -lt $lower ]; then - echo "The difference between $first_num and $second_num are greater than 20%." + echo "The difference between $first_num and $second_num are greater than 15%." exit 1 fi }@@ -41,11 +46,12 @@ check_counts() test_bpf_counters()
tools/perf/tests/shell/stat_bpf_counters.sh check_counts() · line 54
Quoted 10 lines
tools/perf/tests/shell/stat_bpf_counters.sh +3
-2{ printf "Testing --bpf-counters " - base_instructions=$(perf stat --no-big-num -e instructions -- $workload 2>&1 | \ + base_instructions=$(perf stat --no-big-num -e instructions:u -- "${workload[@]}" 2>&1 | \ awk -v i=0 -v c=0 '/instructions/ { \ if ($1 != "<not") { i++; c += $1 } \ } END { if (i > 0) printf "%.0f", c; else print "<not" }') - bpf_instructions=$(perf stat --no-big-num --bpf-counters -e instructions -- $workload 2>&1 | \ + bpf_instructions=$(perf stat --no-big-num --bpf-counters -e instructions:u \ + -- "${workload[@]}" 2>&1 | \
^^^
I ran an AI-assisted backport review, and I have verified the report. It looks valid to me.
The patch uses a Bash array and "${workload[@]}", but 6.12 keeps a /bin/sh shebang. It also lacks the upstream "(exclusive)" marker even though the destination perf dispatcher honors that marker when running tests in parallel. Thus a conforming non-Bash shell cannot run the script, and the test also loses its required resource isolation.
Upstream code with both prerequisites:
#!/bin/bash
# perf stat --bpf-counters test (exclusive)Downstream 6.12.y code:
#!/bin/sh
# perf stat --bpf-counters test
workload=(taskset -c "$CPU" awk
'BEGIN { for (i=0; i<10000000; i++) sum+=i }')The missing commits are 2f5d370dec3f800b44bbf7b68875d521e0af43cd for the Bash shebang and 2532be3d219d8819e59dc52a5ead4696b8354a82 for the exclusive marker.
Maybe we should be pulling in these two backports as well, but note this is perf/ on stable kernels.
thanks,
Harshit
Quoted 14 lines
tools/perf/tests/shell/stat_bpf_counters.sh +3
-1awk -v i=0 -v c=0 '/instructions/ { \ if ($1 != "<not") { i++; c += $1 } \ } END { if (i > 0) printf "%.0f", c; else print "<not" }')@@ -57,7 +63,9 @@ test_bpf_counters() test_bpf_modifier() { printf "Testing bpf event modifier " - stat_output=$(perf stat --no-big-num -e instructions/name=base_instructions/,instructions/name=bpf_instructions/b -- $workload 2>&1) + stat_output=$(perf stat --no-big-num \ + -e instructions/name=base_instructions/u,instructions/name=bpf_instructions/bu \ + -- "${workload[@]}" 2>&1) base_instructions=$(echo "$stat_output"| \ awk -v i=0 -v c=0 '/base_instructions/ { \ if ($1 != "<not") { i++; c += $1 } \
Sasha Levin
maintainerRe: [PATCH 6.12 0360/1376] perf tests: Fix flakiness in BPF counters test on hybrid systems
Quoted 2 lines
The patch uses a Bash array and "${workload[@]}", but 6.12 keeps a
/bin/shshebang.
Reverted on 6.12, 6.6, 6.1 and 5.15. 7.2 and 6.18 already carry the bash shebang, so they keep b02027776ac5 ("perf tests: Fix flakiness in BPF counters test on hybrid systems") as is.
Signature · 2 lines
Thanks, Sasha
Greg Kroah-Hartman
maintainerPATCH 361/1376 perf test brstack: Speed up running test by using tr -s instead of xargs
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Clark <[email protected]>
[ Upstream commit 3178155d292b2b5f0b9f59b3777dc52e029652ba ]
The brstack test runs quite slowly in software models. Part of the reason is "xargs -n1" is quite inefficient in replacing spaces with newlines.
While that's not noticeable on normal machines, it is on software models.
Use "tr -s ' ' '\n'" instead which can do the same transformation, but is much faster. For comparison on an M1 Macbook Pro:
$ time seq -s ' ' 10000 | xargs -n1 > /dev/null
real 0m2.729s user 0m2.009s sys 0m0.914s $ time seq -s ' ' 10000 | tr -s ' ' '\n' | grep '.' > /dev/null
real 0m0.002s user 0m0.001s sys 0m0.001s
The "grep '.'" is also needed to remove any remaining blank lines.
Stable-dep-of: 344d3aec164d ("perf tests: Fix flakiness in branch stack sampling tests")
--- tools/perf/tests/shell/test_brstack.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
tools/perf/tests/shell/test_brstack.sh +2 -2
@@ -30,7 +30,7 @@ test_user_branches() { echo "Testing user branch stack sampling" perf record -o $TMPDIR/perf.data --branch-filter any,save_type,u -- ${TESTPROG} > /dev/null 2>&1 - perf script -i $TMPDIR/perf.data --fields brstacksym | xargs -n1 > $TMPDIR/perf.script + perf script -i $TMPDIR/perf.data --fields brstacksym | tr -s ' ' '\n' > $TMPDIR/perf.script # example of branch entries: # brstack_foo+0x14/brstack_bar+0x40/P/-/-/0/CALL
@@ -59,7 +59,7 @@ test_filter() { echo "Testing branch stack filtering permutation ($test_filter_filter,$test_filter_expect)" perf record -o $TMPDIR/perf.data --branch-filter $test_filter_filter,save_type,u -- ${TESTPROG} > /dev/null 2>&1 - perf script -i $TMPDIR/perf.data --fields brstack | xargs -n1 > $TMPDIR/perf.script + perf script -i $TMPDIR/perf.data --fields brstack | tr -s ' ' '\n' | grep '.' > $TMPDIR/perf.script # fail if we find any branch type that doesn't match any of the expected ones # also consider UNKNOWN branch types (-)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 362/1376 perf tests: Harden branch stack sampling test
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit f3061d526714ac6cc936c48e76a6eb0512c69b1a ]
On continuous testing the perf script output can be empty, or nearly empty, causing tr/grep to exit and due to "set -e" the test traps and fails.
Add some empty file handling that sets the test to skip and make grep and other text rewriting failures non-fatal by adding "|| true".
Committer testing:
root@number:~# grep -m1 "model name" /proc/cpuinfo model name : AMD Ryzen 9 9950X3D 16-Core Processor root@number:~# perf test "Check branch stack sampling" 104: Check branch stack sampling : Ok root@number:~# root@number:~# perf test -vvvvvvv "Check branch stack sampling" 104: Check branch stack sampling: --- start --- test child forked, pid 396047 142d22-142da0 l brstack_bench perf does have symbol 'brstack_bench' Testing user branch stack sampling Testing branch stack filtering permutation (any_call,CALL|IND_CALL|COND_CALL|SYSCALL|IRQ) Testing branch stack filtering permutation (call,CALL|SYSCALL) Testing branch stack filtering permutation (cond,COND) Testing branch stack filtering permutation (any_ret,RET|COND_RET|SYSRET|ERET) Testing branch stack filtering permutation (call,cond,CALL|SYSCALL|COND) Testing branch stack filtering permutation (any_call,cond,CALL|IND_CALL|COND_CALL|IRQ|SYSCALL|COND) Testing branch stack filtering permutation (cond,any_call,any_ret,COND|CALL|IND_CALL|COND_CALL|SYSCALL|IRQ|RET|COND_RET|SYSRET|ERET) ---- end(0) ---- 104: Check branch stack sampling : Ok root@number:~#
Stable-dep-of: 344d3aec164d ("perf tests: Fix flakiness in branch stack sampling tests")
--- tools/perf/tests/shell/test_brstack.sh | 72 +++++++++++++++++++------- 1 file changed, 52 insertions(+), 20 deletions(-)
tools/perf/tests/shell/test_brstack.sh +52 -20
@@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Check branch stack sampling # SPDX-License-Identifier: GPL-2.0
@@ -17,35 +17,50 @@ fi skip_test_missing_symbol brstack_bench +err=0 TMPDIR=$(mktemp -d /tmp/__perf_test.program.XXXXX) TESTPROG="perf test -w brstack" cleanup() { rm -rf $TMPDIR + trap - EXIT TERM INT } -trap cleanup EXIT TERM INT +trap_cleanup() { + set +e + echo "Unexpected signal in ${FUNCNAME[1]}" + cleanup + exit 1 +} +trap trap_cleanup EXIT TERM INT test_user_branches() { echo "Testing user branch stack sampling" - perf record -o $TMPDIR/perf.data --branch-filter any,save_type,u -- ${TESTPROG} > /dev/null 2>&1 - perf script -i $TMPDIR/perf.data --fields brstacksym | tr -s ' ' '\n' > $TMPDIR/perf.script + perf record -o "$TMPDIR/perf.data" --branch-filter any,save_type,u -- ${TESTPROG} > "$TMPDIR/record.txt" 2>&1 + perf script -i "$TMPDIR/perf.data" --fields brstacksym > "$TMPDIR/perf.script" # example of branch entries: # brstack_foo+0x14/brstack_bar+0x40/P/-/-/0/CALL - set -x - grep -E -m1 "^brstack_bench\+[^ ]*/brstack_foo\+[^ ]*/IND_CALL/.*$" $TMPDIR/perf.script - grep -E -m1 "^brstack_foo\+[^ ]*/brstack_bar\+[^ ]*/CALL/.*$" $TMPDIR/perf.script - grep -E -m1 "^brstack_bench\+[^ ]*/brstack_foo\+[^ ]*/CALL/.*$" $TMPDIR/perf.script - grep -E -m1 "^brstack_bench\+[^ ]*/brstack_bar\+[^ ]*/CALL/.*$" $TMPDIR/perf.script - grep -E -m1 "^brstack_bar\+[^ ]*/brstack_foo\+[^ ]*/RET/.*$" $TMPDIR/perf.script - grep -E -m1 "^brstack_foo\+[^ ]*/brstack_bench\+[^ ]*/RET/.*$" $TMPDIR/perf.script - grep -E -m1 "^brstack_bench\+[^ ]*/brstack_bench\+[^ ]*/COND/.*$" $TMPDIR/perf.script - grep -E -m1 "^brstack\+[^ ]*/brstack\+[^ ]*/UNCOND/.*$" $TMPDIR/perf.script - set +x - + expected=( + "^brstack_bench\+[^ ]*/brstack_foo\+[^ ]*/IND_CALL/.*$" + "^brstack_foo\+[^ ]*/brstack_bar\+[^ ]*/CALL/.*$" + "^brstack_bench\+[^ ]*/brstack_foo\+[^ ]*/CALL/.*$" + "^brstack_bench\+[^ ]*/brstack_bar\+[^ ]*/CALL/.*$" + "^brstack_bar\+[^ ]*/brstack_foo\+[^ ]*/RET/.*$" + "^brstack_foo\+[^ ]*/brstack_bench\+[^ ]*/RET/.*$" + "^brstack_bench\+[^ ]*/brstack_bench\+[^ ]*/COND/.*$" + "^brstack\+[^ ]*/brstack\+[^ ]*/UNCOND/.*$" + ) + for x in "${expected[@]}" + do + if ! tr -s ' ' '\n' < "$TMPDIR/perf.script" | grep -E -m1 -q "$x" + then + echo "Branches missing $x" + err=1 + fi + done # some branch types are still not being tested: # IND COND_CALL COND_RET SYSCALL SYSRET IRQ SERROR NO_TX }
@@ -57,14 +72,28 @@ test_filter() { test_filter_expect=$2 echo "Testing branch stack filtering permutation ($test_filter_filter,$test_filter_expect)" - - perf record -o $TMPDIR/perf.data --branch-filter $test_filter_filter,save_type,u -- ${TESTPROG} > /dev/null 2>&1 - perf script -i $TMPDIR/perf.data --fields brstack | tr -s ' ' '\n' | grep '.' > $TMPDIR/perf.script + perf record -o "$TMPDIR/perf.data" --branch-filter "$test_filter_filter,save_type,u" -- ${TESTPROG} > "$TMPDIR/record.txt" 2>&1 + perf script -i "$TMPDIR/perf.data" --fields brstack > "$TMPDIR/perf.script" # fail if we find any branch type that doesn't match any of the expected ones # also consider UNKNOWN branch types (-) - if grep -E -vm1 "^[^ ]*/($test_filter_expect|-|( *))/.*$" $TMPDIR/perf.script; then - return 1 + if [ ! -s "$TMPDIR/perf.script" ] + then + echo "Empty script output" + err=1 + return + fi + # Look for lines not matching test_filter_expect ignoring issues caused + # by empty output + tr -s ' ' '\n' < "$TMPDIR/perf.script" | grep '.' | \ + grep -E -vm1 "^[^ ]*/($test_filter_expect|-|( *))/.*$" \ + > "$TMPDIR/perf.script-filtered" || true + if [ -s "$TMPDIR/perf.script-filtered" ] + then + echo "Unexpected branch filter in script output" + cat "$TMPDIR/perf.script" + err=1 + return fi }
@@ -80,3 +109,6 @@ test_filter "any_ret" "RET|COND_RET|SYSRET|ERET" test_filter "call,cond" "CALL|SYSCALL|COND" test_filter "any_call,cond" "CALL|IND_CALL|COND_CALL|IRQ|SYSCALL|COND" test_filter "cond,any_call,any_ret" "COND|CALL|IND_CALL|COND_CALL|SYSCALL|IRQ|RET|COND_RET|SYSRET|ERET" + +cleanup +exit $err
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 363/1376 perf test: Refactor brstack test
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Clark <[email protected]>
[ Upstream commit f15548b277cc107d41b88b1a63bd4942b703666b ]
check_branches() will be used by other tests in a later commit so make it a function. And the any_call filters are duplicated and will also be extended in a later commit, so move them to a variable.
No functional changes intended.
Stable-dep-of: 344d3aec164d ("perf tests: Fix flakiness in branch stack sampling tests")
--- tools/perf/tests/shell/test_brstack.sh | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-)
tools/perf/tests/shell/test_brstack.sh +13 -8
@@ -34,6 +34,13 @@ trap_cleanup() { } trap trap_cleanup EXIT TERM INT +check_branches() { + if ! tr -s ' ' '\n' < "$TMPDIR/perf.script" | grep -E -m1 -q "$1"; then + echo "Branches missing $1" + err=1 + fi +} + test_user_branches() { echo "Testing user branch stack sampling"
@@ -55,11 +62,7 @@ test_user_branches() { ) for x in "${expected[@]}" do - if ! tr -s ' ' '\n' < "$TMPDIR/perf.script" | grep -E -m1 -q "$x" - then - echo "Branches missing $x" - err=1 - fi + check_branches "$x" done # some branch types are still not being tested: # IND COND_CALL COND_RET SYSCALL SYSRET IRQ SERROR NO_TX
@@ -101,14 +104,16 @@ set -e test_user_branches -test_filter "any_call" "CALL|IND_CALL|COND_CALL|SYSCALL|IRQ" +any_call="CALL|IND_CALL|COND_CALL|SYSCALL|IRQ" + +test_filter "any_call" "$any_call" test_filter "call" "CALL|SYSCALL" test_filter "cond" "COND" test_filter "any_ret" "RET|COND_RET|SYSRET|ERET" test_filter "call,cond" "CALL|SYSCALL|COND" -test_filter "any_call,cond" "CALL|IND_CALL|COND_CALL|IRQ|SYSCALL|COND" -test_filter "cond,any_call,any_ret" "COND|CALL|IND_CALL|COND_CALL|SYSCALL|IRQ|RET|COND_RET|SYSRET|ERET" +test_filter "any_call,cond" "$any_call|COND" +test_filter "any_call,cond,any_ret" "$any_call|COND|RET|COND_RET" cleanup exit $err
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 364/1376 perf test: Add syscall and address tests to brstack test
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Clark <[email protected]>
[ Upstream commit 11e59335b0d1c4bc259ee6f0533e04c4b3a9f1dd ]
Test that SYSCALL type branches are emitted from the expected 'getppid' symbol. Test that when only 'k' is used, sources addresses are all in the kernel. Test that no kernel addresses leak by checking for them in the 'u' test.
Stable-dep-of: 344d3aec164d ("perf tests: Fix flakiness in branch stack sampling tests")
--- tools/perf/tests/shell/test_brstack.sh | 61 +++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-)
tools/perf/tests/shell/test_brstack.sh +60 -1
@@ -64,8 +64,50 @@ test_user_branches() { do check_branches "$x" done + + # Dump addresses only this time + perf script -i "$TMPDIR/perf.data" --fields brstack | \ + tr ' ' '\n' > "$TMPDIR/perf.script" + + # There should be no kernel addresses with the u option, in either + # source or target addresses. + if grep -E -m1 "0x[89a-f][0-9a-f]{15}" $TMPDIR/perf.script; then + echo "ERROR: Kernel address found in user mode" + err=1 + fi # some branch types are still not being tested: - # IND COND_CALL COND_RET SYSCALL SYSRET IRQ SERROR NO_TX + # IND COND_CALL COND_RET SYSRET IRQ SERROR NO_TX +} + + +test_kernel_branches() { + echo "Testing that k option only includes kernel source addresses" + + if ! perf record --branch-filter any,k -o- -- true > /dev/null; then + echo "skip: not enough privileges" + else + perf record -o $TMPDIR/perf.data --branch-filter any,k -- \ + perf bench syscall basic --loop 1000 + perf script -i $TMPDIR/perf.data --fields brstack | \ + tr ' ' '\n' > $TMPDIR/perf.script + + # Example of branch entries: + # "0xffffffff93bda241/0xffffffff93bda20f/M/-/-/..." + # Source addresses come first and target address can be either + # userspace or kernel even with k option, as long as the source + # is in kernel. + + #Look for source addresses with top bit set + if ! grep -E -m1 "^0x[89a-f][0-9a-f]{15}" $TMPDIR/perf.script; then + echo "ERROR: Kernel branches missing" + err=1 + fi + # Look for no source addresses without top bit set + if grep -E -m1 "^0x[0-7][0-9a-f]{0,15}" $TMPDIR/perf.script; then + echo "ERROR: User branches found with kernel filter" + err=1 + fi + fi } # first argument <arg0> is the argument passed to "--branch-stack <arg0>,save_type,u"
@@ -100,9 +142,26 @@ test_filter() { fi } +test_syscall() { + echo "Testing syscalls" + # skip if perf doesn't have enough privileges + if ! perf record --branch-filter any,k -o- -- true > /dev/null; then + echo "skip: not enough privileges" + else + perf record -o $TMPDIR/perf.data --branch-filter \ + any_call,save_type,u,k -c 10000 -- \ + perf bench syscall basic --loop 1000 + perf script -i $TMPDIR/perf.data --fields brstacksym | \ + tr ' ' '\n' > $TMPDIR/perf.script + + check_branches "getppid[^ ]*/SYSCALL/" + fi +} set -e test_user_branches +test_syscall +test_kernel_branches any_call="CALL|IND_CALL|COND_CALL|SYSCALL|IRQ"
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 365/1376 perf test: Extend branch stack sampling test for Arm64 BRBE
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Clark <[email protected]>
[ Upstream commit 9f0fa213790e3633d37e981386da99149573135b ]
BRBE emits IRQ and ERET branches for branching and returning from trapped instructions. Add a test that loops on a trapped instruction (MRS - Read special register) for this.
Extend the expected 'any_call' branches to include FAULT_DATA and FAULT_INST as these are emitted by BRBE.
Stable-dep-of: 344d3aec164d ("perf tests: Fix flakiness in branch stack sampling tests")
--- tools/perf/tests/builtin-test.c | 1 + tools/perf/tests/shell/test_brstack.sh | 26 ++++++++++++++++++++- tools/perf/tests/tests.h | 1 + tools/perf/tests/workloads/Build | 2 ++ tools/perf/tests/workloads/traploop.c | 31 ++++++++++++++++++++++++++ 5 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 tools/perf/tests/workloads/traploop.c
tools/perf/tests/builtin-test.c +1 -0
@@ -153,6 +153,7 @@ static struct test_workload *workloads[] = { &workload__brstack, &workload__datasym, &workload__landlock, + &workload__traploop, };static int num_subtests (const struct test_suite *t)
tools/perf/tests/shell/test_brstack.sh +25 -1
@@ -34,6 +34,10 @@ trap_cleanup() { } trap trap_cleanup EXIT TERM INT +is_arm64() { + [ "$(uname -m)" = "aarch64" ]; +} + check_branches() { if ! tr -s ' ' '\n' < "$TMPDIR/perf.script" | grep -E -m1 -q "$1"; then echo "Branches missing $1"
@@ -76,9 +80,24 @@ test_user_branches() { err=1 fi # some branch types are still not being tested: - # IND COND_CALL COND_RET SYSRET IRQ SERROR NO_TX + # IND COND_CALL COND_RET SYSRET SERROR NO_TX } +test_trap_eret_branches() { + echo "Testing trap & eret branches" + if ! is_arm64; then + echo "skip: not arm64" + else + perf record -o $TMPDIR/perf.data --branch-filter any,save_type,u,k -- \ + perf test -w traploop 1000 + perf script -i $TMPDIR/perf.data --fields brstacksym | \ + tr ' ' '\n' > $TMPDIR/perf.script + + # BRBINF<n>.TYPE == TRAP are mapped to PERF_BR_IRQ by the BRBE driver + check_branches "^trap_bench\+[^ ]+/[^ ]/IRQ/" + check_branches "^[^ ]+/trap_bench\+[^ ]+/ERET/" + fi +} test_kernel_branches() { echo "Testing that k option only includes kernel source addresses"
@@ -162,9 +181,14 @@ set -e test_user_branches test_syscall test_kernel_branches +test_trap_eret_branches any_call="CALL|IND_CALL|COND_CALL|SYSCALL|IRQ" +if is_arm64; then + any_call="$any_call|FAULT_DATA|FAULT_INST" +fi + test_filter "any_call" "$any_call" test_filter "call" "CALL|SYSCALL" test_filter "cond" "COND"
tools/perf/tests/tests.h +1 -0
@@ -206,6 +206,7 @@ DECLARE_WORKLOAD(sqrtloop);DECLARE_WORKLOAD (brstack);DECLARE_WORKLOAD (datasym);DECLARE_WORKLOAD (landlock); +DECLARE_WORKLOAD (traploop);extern const char *dso_to_test;extern const char *test_objdump_path;
tools/perf/tests/workloads/Build +2 -0
@@ -7,8 +7,10 @@ perf-test-y += sqrtloop.o perf-test-y += brstack.o perf-test-y += datasym.o perf-test-y += landlock.o +perf-test-y += traploop.o CFLAGS_sqrtloop.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE CFLAGS_leafloop.o = -g -O0 -fno-inline -fno-omit-frame-pointer -U_FORTIFY_SOURCE CFLAGS_brstack.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE CFLAGS_datasym.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE +CFLAGS_traploop.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
tools/perf/tests/workloads/traploop.c new file +31 -0
@@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <stdlib.h> +#include "../tests.h" + +#define BENCH_RUNS 999999 + +#ifdef __aarch64__ +static void trap_bench (void ) +{ +unsigned long val; + + asm("mrs %0, ID_AA64ISAR0_EL1" :"=r" (val));/* TRAP + ERET */ +} +#else +static void trap_bench (void ) { } +#endif + +static int traploop (int argc,const char **argv) +{ +int num_loops =BENCH_RUNS ; + +if (argc >0 ) + num_loops =atoi (argv[0 ]); + +for (int i =0 ; i < num_loops; i++) +trap_bench (); + +return 0 ; +} + +DEFINE_WORKLOAD (traploop);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 366/1376 perf test: Fixes for check branch stack sampling
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 86d1095fdb7017a93e9d7be875775f7e5aa5c2f5 ]
When filtering branch stack samples on user events they sample in user land but may have come from the kernel. Aarch64 avoids leaking the kernel address for kaslr reasons but other platforms, for now, don't. Be more permissive in allowing kernel addresses in the source of user branch stacks.
When filtering branch stack samples on kernel events they sample in kernel land but may have come from user land. Avoid the target being a user address but allow the source to be in user land. Aarch64 may not leak the user land addresses (making them 0) but other platforms do. As the kernel address sampling implies privelege, just allow this.
Increase the duration of the system call sampling test to make the likelihood of sampling a system call higher (increased from 1000 to 8000 loops - a number found through experimentation on an Intel Tigerlake laptop), also make the period of the event a prime number.
Put unneeded perf record output into a temporary file so that the test output isn't cluttered. More clearly state which test is running and the pass, fail or skipped result of the test.
These changes make the test on an Intel tigerlake laptop reliably pass rather than reliably fail.
Stable-dep-of: 344d3aec164d ("perf tests: Fix flakiness in branch stack sampling tests")
--- tools/perf/tests/shell/test_brstack.sh | 146 ++++++++++++++++--------- 1 file changed, 96 insertions(+), 50 deletions(-)
tools/perf/tests/shell/test_brstack.sh +96 -50
@@ -38,9 +38,13 @@ is_arm64() { [ "$(uname -m)" = "aarch64" ]; } +has_kaslr_bug() { + [ "$(uname -m)" != "aarch64" ]; +} + check_branches() { if ! tr -s ' ' '\n' < "$TMPDIR/perf.script" | grep -E -m1 -q "$1"; then - echo "Branches missing $1" + echo "ERROR: Branches missing $1" err=1 fi }
@@ -48,6 +52,8 @@ check_branches() { test_user_branches() { echo "Testing user branch stack sampling" + start_err=$err + err=0 perf record -o "$TMPDIR/perf.data" --branch-filter any,save_type,u -- ${TESTPROG} > "$TMPDIR/record.txt" 2>&1 perf script -i "$TMPDIR/perf.data" --fields brstacksym > "$TMPDIR/perf.script"
@@ -73,59 +79,88 @@ test_user_branches() { perf script -i "$TMPDIR/perf.data" --fields brstack | \ tr ' ' '\n' > "$TMPDIR/perf.script" - # There should be no kernel addresses with the u option, in either - # source or target addresses. - if grep -E -m1 "0x[89a-f][0-9a-f]{15}" $TMPDIR/perf.script; then - echo "ERROR: Kernel address found in user mode" + # There should be no kernel addresses in the target with the u option. + local regex="0x[89a-f][0-9a-f]{15}" + if has_kaslr_bug; then + # If the system has a kaslr bug that may leak kernel addresses + # in the source of something like an ERET/SYSRET. Make the regex + # more specific and just check the target address is in user + # code. + regex="^0x[0-9a-f]{0,16}/0x[89a-f][0-9a-f]{15}/" + fi + if grep -q -E -m1 "$regex" $TMPDIR/perf.script; then + echo "Testing user branch stack sampling [Failed kernel address found in user mode]" err=1 fi # some branch types are still not being tested: # IND COND_CALL COND_RET SYSRET SERROR NO_TX + if [ $err -eq 0 ]; then + echo "Testing user branch stack sampling [Passed]" + err=$start_err + else + echo "Testing user branch stack sampling [Failed]" + fi } test_trap_eret_branches() { echo "Testing trap & eret branches" + if ! is_arm64; then - echo "skip: not arm64" + echo "Testing trap & eret branches [Skipped not arm64]" + return + fi + start_err=$err + err=0 + perf record -o $TMPDIR/perf.data --branch-filter any,save_type,u,k -- \ + perf test -w traploop 1000 > "$TMPDIR/record.txt" 2>&1 + perf script -i $TMPDIR/perf.data --fields brstacksym | \ + tr ' ' '\n' > $TMPDIR/perf.script + + # BRBINF<n>.TYPE == TRAP are mapped to PERF_BR_IRQ by the BRBE driver + check_branches "^trap_bench\+[^ ]+/[^ ]/IRQ/" + check_branches "^[^ ]+/trap_bench\+[^ ]+/ERET/" + if [ $err -eq 0 ]; then + echo "Testing trap & eret branches [Passed]" + err=$start_err else - perf record -o $TMPDIR/perf.data --branch-filter any,save_type,u,k -- \ - perf test -w traploop 1000 - perf script -i $TMPDIR/perf.data --fields brstacksym | \ - tr ' ' '\n' > $TMPDIR/perf.script - - # BRBINF<n>.TYPE == TRAP are mapped to PERF_BR_IRQ by the BRBE driver - check_branches "^trap_bench\+[^ ]+/[^ ]/IRQ/" - check_branches "^[^ ]+/trap_bench\+[^ ]+/ERET/" + echo "Testing trap & eret branches [Failed]" fi } test_kernel_branches() { - echo "Testing that k option only includes kernel source addresses" + echo "Testing kernel branch sampling" - if ! perf record --branch-filter any,k -o- -- true > /dev/null; then - echo "skip: not enough privileges" + if ! perf record --branch-filter any,k -o- -- true > "$TMPDIR/record.txt" 2>&1; then + echo "Testing that k option [Skipped not enough privileges]" + return + fi + start_err=$err + err=0 + perf record -o $TMPDIR/perf.data --branch-filter any,k -- \ + perf bench syscall basic --loop 1000 > "$TMPDIR/record.txt" 2>&1 + perf script -i $TMPDIR/perf.data --fields brstack | \ + tr ' ' '\n' > $TMPDIR/perf.script + + # Example of branch entries: + # "0xffffffff93bda241/0xffffffff93bda20f/M/-/-/..." + # Source addresses come first in user or kernel code. Next is the target + # address that must be in the kernel. + + # Look for source addresses with top bit set + if ! grep -q -E -m1 "^0x[89a-f][0-9a-f]{15}" $TMPDIR/perf.script; then + echo "Testing kernel branch sampling [Failed kernel branches missing]" + err=1 + fi + # Look for no target addresses without top bit set + if grep -q -E -m1 "^0x[0-9a-f]{0,16}/0x[0-7][0-9a-f]{1,15}/" $TMPDIR/perf.script; then + echo "Testing kernel branch sampling [Failed user branches found]" + err=1 + fi + if [ $err -eq 0 ]; then + echo "Testing kernel branch sampling [Passed]" + err=$start_err else - perf record -o $TMPDIR/perf.data --branch-filter any,k -- \ - perf bench syscall basic --loop 1000 - perf script -i $TMPDIR/perf.data --fields brstack | \ - tr ' ' '\n' > $TMPDIR/perf.script - - # Example of branch entries: - # "0xffffffff93bda241/0xffffffff93bda20f/M/-/-/..." - # Source addresses come first and target address can be either - # userspace or kernel even with k option, as long as the source - # is in kernel. - - #Look for source addresses with top bit set - if ! grep -E -m1 "^0x[89a-f][0-9a-f]{15}" $TMPDIR/perf.script; then - echo "ERROR: Kernel branches missing" - err=1 - fi - # Look for no source addresses without top bit set - if grep -E -m1 "^0x[0-7][0-9a-f]{0,15}" $TMPDIR/perf.script; then - echo "ERROR: User branches found with kernel filter" - err=1 - fi + echo "Testing kernel branch sampling [Failed]" fi }
@@ -136,14 +171,15 @@ test_filter() { test_filter_expect=$2 echo "Testing branch stack filtering permutation ($test_filter_filter,$test_filter_expect)" - perf record -o "$TMPDIR/perf.data" --branch-filter "$test_filter_filter,save_type,u" -- ${TESTPROG} > "$TMPDIR/record.txt" 2>&1 + perf record -o "$TMPDIR/perf.data" --branch-filter "$test_filter_filter,save_type,u" -- \ + ${TESTPROG} > "$TMPDIR/record.txt" 2>&1 perf script -i "$TMPDIR/perf.data" --fields brstack > "$TMPDIR/perf.script" # fail if we find any branch type that doesn't match any of the expected ones # also consider UNKNOWN branch types (-) if [ ! -s "$TMPDIR/perf.script" ] then - echo "Empty script output" + echo "Testing branch stack filtering [Failed empty script output]" err=1 return fi
@@ -154,26 +190,36 @@ test_filter() { > "$TMPDIR/perf.script-filtered" || true if [ -s "$TMPDIR/perf.script-filtered" ] then - echo "Unexpected branch filter in script output" + echo "Testing branch stack filtering [Failed unexpected branch filter]" cat "$TMPDIR/perf.script" err=1 return fi + echo "Testing branch stack filtering [Passed]" } test_syscall() { echo "Testing syscalls" # skip if perf doesn't have enough privileges - if ! perf record --branch-filter any,k -o- -- true > /dev/null; then - echo "skip: not enough privileges" + if ! perf record --branch-filter any,k -o- -- true > "$TMPDIR/record.txt" 2>&1; then + echo "Testing syscalls [Skipped: not enough privileges]" + return + fi + start_err=$err + err=0 + perf record -o $TMPDIR/perf.data --branch-filter \ + any_call,save_type,u,k -c 10007 -- \ + perf bench syscall basic --loop 8000 > "$TMPDIR/record.txt" 2>&1 + perf script -i $TMPDIR/perf.data --fields brstacksym | \ + tr ' ' '\n' > $TMPDIR/perf.script + + check_branches "getppid[^ ]*/SYSCALL/" + + if [ $err -eq 0 ]; then + echo "Testing syscalls [Passed]" + err=$start_err else - perf record -o $TMPDIR/perf.data --branch-filter \ - any_call,save_type,u,k -c 10000 -- \ - perf bench syscall basic --loop 1000 - perf script -i $TMPDIR/perf.data --fields brstacksym | \ - tr ' ' '\n' > $TMPDIR/perf.script - - check_branches "getppid[^ ]*/SYSCALL/" + echo "Testing syscalls [Failed]" fi } set -e
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 367/1376 perf tests: Fix flakiness in branch stack sampling tests
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 344d3aec164dba83a5520f23a0d46e13e904a205 ]
The branch stack sampling test (test 130) runs short iteration-based workloads to verify syscall, kernel, and trap branch stack sampling. Specifically, test_syscall() and test_kernel_branches() run perf bench syscall basic with loop counts of 8000 and 1000, and test_trap_eret_branches() runs traploop with 1000 iterations.
Because these loop limits are extremely small, the total benchmark runtimes last only a few milliseconds (or less). Under high load, virtualization, or coarse sampling conditions, PMU cycle sampling fails to capture enough samples inside the brief benchmark loops. This leads to false negatives where the script output lacks the expected syscall, kernel, or trap branch entries (e.g. "ERROR: Branches missing getppid[^ ]*/SYSCALL/").
Fix this by increasing the workload loop counts to 100,000 across all three test sections. Running 100,000 loops still finishes virtually instantaneously (less than 0.1 seconds), but generates enough iterations to guarantee robust branch stack capture.
--- tools/perf/tests/shell/test_brstack.sh | 107 +++++++++++++++---------- 1 file changed, 66 insertions(+), 41 deletions(-)
tools/perf/tests/shell/test_brstack.sh +66 -41
@@ -110,20 +110,29 @@ test_trap_eret_branches() { return fi start_err=$err - err=0 - perf record -o $TMPDIR/perf.data --branch-filter any,save_type,u,k -- \ - perf test -w traploop 1000 > "$TMPDIR/record.txt" 2>&1 - perf script -i $TMPDIR/perf.data --fields brstacksym | \ - tr ' ' '\n' > $TMPDIR/perf.script - - # BRBINF<n>.TYPE == TRAP are mapped to PERF_BR_IRQ by the BRBE driver - check_branches "^trap_bench\+[^ ]+/[^ ]/IRQ/" - check_branches "^[^ ]+/trap_bench\+[^ ]+/ERET/" - if [ $err -eq 0 ]; then + local ret=1 + for loops in 1000 10000 100000; do + err=0 + perf record -o $TMPDIR/perf.data --branch-filter any,save_type,u,k -- \ + perf test -w traploop $loops > "$TMPDIR/record.txt" 2>&1 + perf script -i $TMPDIR/perf.data --fields brstacksym | \ + tr ' ' '\n' > $TMPDIR/perf.script + + # BRBINF<n>.TYPE == TRAP are mapped to PERF_BR_IRQ by the BRBE driver + check_branches "^trap_bench\+[^ ]+/[^ ]/IRQ/" + check_branches "^[^ ]+/trap_bench\+[^ ]+/ERET/" + if [ $err -eq 0 ]; then + ret=0 + break + fi + done + + if [ $ret -eq 0 ]; then echo "Testing trap & eret branches [Passed]" err=$start_err else echo "Testing trap & eret branches [Failed]" + err=1 fi }
@@ -135,32 +144,40 @@ test_kernel_branches() { return fi start_err=$err - err=0 - perf record -o $TMPDIR/perf.data --branch-filter any,k -- \ - perf bench syscall basic --loop 1000 > "$TMPDIR/record.txt" 2>&1 - perf script -i $TMPDIR/perf.data --fields brstack | \ - tr ' ' '\n' > $TMPDIR/perf.script - - # Example of branch entries: - # "0xffffffff93bda241/0xffffffff93bda20f/M/-/-/..." - # Source addresses come first in user or kernel code. Next is the target - # address that must be in the kernel. - - # Look for source addresses with top bit set - if ! grep -q -E -m1 "^0x[89a-f][0-9a-f]{15}" $TMPDIR/perf.script; then - echo "Testing kernel branch sampling [Failed kernel branches missing]" - err=1 - fi - # Look for no target addresses without top bit set - if grep -q -E -m1 "^0x[0-9a-f]{0,16}/0x[0-7][0-9a-f]{1,15}/" $TMPDIR/perf.script; then - echo "Testing kernel branch sampling [Failed user branches found]" - err=1 - fi - if [ $err -eq 0 ]; then + local ret=1 + for loops in 1000 10000 100000; do + err=0 + perf record -o $TMPDIR/perf.data --branch-filter any,k -- \ + perf bench syscall basic --loop $loops > "$TMPDIR/record.txt" 2>&1 + perf script -i $TMPDIR/perf.data --fields brstack | \ + tr ' ' '\n' > $TMPDIR/perf.script + + # Example of branch entries: + # "0xffffffff93bda241/0xffffffff93bda20f/M/-/-/..." + # Source addresses come first in user or kernel code. Next is the target + # address that must be in the kernel. + + # Look for source addresses with top bit set + if ! grep -q -E -m1 "^0x[89a-f][0-9a-f]{15}" $TMPDIR/perf.script; then + err=1 + fi + # Look for no target addresses without top bit set + if grep -q -E -m1 "^0x[0-9a-f]{0,16}/0x[0-7][0-9a-f]{1,15}/" \ + $TMPDIR/perf.script; then + err=1 + fi + if [ $err -eq 0 ]; then + ret=0 + break + fi + done + + if [ $ret -eq 0 ]; then echo "Testing kernel branch sampling [Passed]" err=$start_err else echo "Testing kernel branch sampling [Failed]" + err=1 fi }
@@ -206,20 +223,28 @@ test_syscall() { return fi start_err=$err - err=0 - perf record -o $TMPDIR/perf.data --branch-filter \ - any_call,save_type,u,k -c 10007 -- \ - perf bench syscall basic --loop 8000 > "$TMPDIR/record.txt" 2>&1 - perf script -i $TMPDIR/perf.data --fields brstacksym | \ - tr ' ' '\n' > $TMPDIR/perf.script - - check_branches "getppid[^ ]*/SYSCALL/" + local ret=1 + for loops in 8000 30000 100000; do + err=0 + perf record -o $TMPDIR/perf.data --branch-filter \ + any_call,save_type,u,k -c 10007 -- \ + perf bench syscall basic --loop $loops > "$TMPDIR/record.txt" 2>&1 + perf script -i $TMPDIR/perf.data --fields brstacksym | \ + tr ' ' '\n' > $TMPDIR/perf.script + + check_branches "getppid[^ ]*/SYSCALL/" + if [ $err -eq 0 ]; then + ret=0 + break + fi + done - if [ $err -eq 0 ]; then + if [ $ret -eq 0 ]; then echo "Testing syscalls [Passed]" err=$start_err else echo "Testing syscalls [Failed]" + err=1 fi } set -e
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 368/1376 regulator: tps6594-regulator: Constify struct tps6594_regulator_irq_type
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christophe JAILLET <[email protected]>
[ Upstream commit c266209eaef4fef863363557817f7d6a68314321 ]
'struct tps6594_regulator_irq_type' are not modified in this driver.
Constifying this structure moves some data to a read-only section, so increases overall security.
On a x86_64, with allmodconfig, as an example:
Before:
======
text data bss dec hex filename
25645 14480 64 40189 9cfd drivers/regulator/tps6594-regulator.o
After:
=====
text data bss dec hex filename
27949 12176 64 40189 9cfd drivers/regulator/tps6594-regulator.o
Stable-dep-of: 7fd28093b3ef ("regulator: tps6594: Fix device node reference leaks in multiphase loop")
--- drivers/regulator/tps6594-regulator.c | 60 +++++++++++++-------------- 1 file changed, 30 insertions(+), 30 deletions(-)
drivers/regulator/tps6594-regulator.c +30 -30
@@ -56,7 +56,7 @@ struct tps6594_regulator_irq_type {unsigned long event; }; -static struct tps6594_regulator_irq_type tps6594_ext_regulator_irq_types[] = { +static const struct tps6594_regulator_irq_type tps6594_ext_regulator_irq_types[] = { {TPS6594_IRQ_NAME_VCCA_OV ,"VCCA" ,"overvoltage" ,REGULATOR_EVENT_OVER_VOLTAGE_WARN }, {TPS6594_IRQ_NAME_VCCA_UV ,"VCCA" ,"undervoltage" ,REGULATOR_EVENT_UNDER_VOLTAGE }, {TPS6594_IRQ_NAME_VMON1_OV ,"VMON1" ,"overvoltage" ,REGULATOR_EVENT_OVER_VOLTAGE_WARN },
@@ -69,7 +69,7 @@ static struct tps6594_regulator_irq_type tps6594_ext_regulator_irq_types[] = { REGULATOR_EVENT_OVER_VOLTAGE_WARN }, }; -static struct tps6594_regulator_irq_type tps65224_ext_regulator_irq_types[] = { +static const struct tps6594_regulator_irq_type tps65224_ext_regulator_irq_types[] = { {TPS65224_IRQ_NAME_VCCA_UVOV ,"VCCA" ,"voltage out of range" ,REGULATOR_EVENT_REGULATION_OUT }, {TPS65224_IRQ_NAME_VMON1_UVOV ,"VMON1" ,"voltage out of range" ,
@@ -80,13 +80,13 @@ static struct tps6594_regulator_irq_type tps65224_ext_regulator_irq_types[] = {struct tps6594_regulator_irq_data {struct device *dev; -struct tps6594_regulator_irq_type *type; +const struct tps6594_regulator_irq_type *type;struct regulator_dev *rdev; };struct tps6594_ext_regulator_irq_data {struct device *dev; -struct tps6594_regulator_irq_type *type; +const struct tps6594_regulator_irq_type *type; }; #define TPS6594_REGULATOR(_name, _of, _id, _type, _ops, _n, _vr, _vm, _er, \
@@ -262,7 +262,7 @@ static const struct regulator_desc tps65224_buck_regs[] = { 4, 0, 0, NULL, 0, 0), }; -static struct tps6594_regulator_irq_type tps6594_buck1_irq_types[] = { +static const struct tps6594_regulator_irq_type tps6594_buck1_irq_types[] = { {TPS6594_IRQ_NAME_BUCK1_OV ,"BUCK1" ,"overvoltage" ,REGULATOR_EVENT_OVER_VOLTAGE_WARN }, {TPS6594_IRQ_NAME_BUCK1_UV ,"BUCK1" ,"undervoltage" ,REGULATOR_EVENT_UNDER_VOLTAGE }, {TPS6594_IRQ_NAME_BUCK1_SC ,"BUCK1" ,"short circuit" ,REGULATOR_EVENT_REGULATION_OUT },
@@ -270,7 +270,7 @@ static struct tps6594_regulator_irq_type tps6594_buck1_irq_types[] = { REGULATOR_EVENT_OVER_CURRENT }, }; -static struct tps6594_regulator_irq_type tps6594_buck2_irq_types[] = { +static const struct tps6594_regulator_irq_type tps6594_buck2_irq_types[] = { {TPS6594_IRQ_NAME_BUCK2_OV ,"BUCK2" ,"overvoltage" ,REGULATOR_EVENT_OVER_VOLTAGE_WARN }, {TPS6594_IRQ_NAME_BUCK2_UV ,"BUCK2" ,"undervoltage" ,REGULATOR_EVENT_UNDER_VOLTAGE }, {TPS6594_IRQ_NAME_BUCK2_SC ,"BUCK2" ,"short circuit" ,REGULATOR_EVENT_REGULATION_OUT },
@@ -278,7 +278,7 @@ static struct tps6594_regulator_irq_type tps6594_buck2_irq_types[] = { REGULATOR_EVENT_OVER_CURRENT }, }; -static struct tps6594_regulator_irq_type tps6594_buck3_irq_types[] = { +static const struct tps6594_regulator_irq_type tps6594_buck3_irq_types[] = { {TPS6594_IRQ_NAME_BUCK3_OV ,"BUCK3" ,"overvoltage" ,REGULATOR_EVENT_OVER_VOLTAGE_WARN }, {TPS6594_IRQ_NAME_BUCK3_UV ,"BUCK3" ,"undervoltage" ,REGULATOR_EVENT_UNDER_VOLTAGE }, {TPS6594_IRQ_NAME_BUCK3_SC ,"BUCK3" ,"short circuit" ,REGULATOR_EVENT_REGULATION_OUT },
@@ -286,7 +286,7 @@ static struct tps6594_regulator_irq_type tps6594_buck3_irq_types[] = { REGULATOR_EVENT_OVER_CURRENT }, }; -static struct tps6594_regulator_irq_type tps6594_buck4_irq_types[] = { +static const struct tps6594_regulator_irq_type tps6594_buck4_irq_types[] = { {TPS6594_IRQ_NAME_BUCK4_OV ,"BUCK4" ,"overvoltage" ,REGULATOR_EVENT_OVER_VOLTAGE_WARN }, {TPS6594_IRQ_NAME_BUCK4_UV ,"BUCK4" ,"undervoltage" ,REGULATOR_EVENT_UNDER_VOLTAGE }, {TPS6594_IRQ_NAME_BUCK4_SC ,"BUCK4" ,"short circuit" ,REGULATOR_EVENT_REGULATION_OUT },
@@ -294,7 +294,7 @@ static struct tps6594_regulator_irq_type tps6594_buck4_irq_types[] = { REGULATOR_EVENT_OVER_CURRENT }, }; -static struct tps6594_regulator_irq_type tps6594_buck5_irq_types[] = { +static const struct tps6594_regulator_irq_type tps6594_buck5_irq_types[] = { {TPS6594_IRQ_NAME_BUCK5_OV ,"BUCK5" ,"overvoltage" ,REGULATOR_EVENT_OVER_VOLTAGE_WARN }, {TPS6594_IRQ_NAME_BUCK5_UV ,"BUCK5" ,"undervoltage" ,REGULATOR_EVENT_UNDER_VOLTAGE }, {TPS6594_IRQ_NAME_BUCK5_SC ,"BUCK5" ,"short circuit" ,REGULATOR_EVENT_REGULATION_OUT },
@@ -302,7 +302,7 @@ static struct tps6594_regulator_irq_type tps6594_buck5_irq_types[] = { REGULATOR_EVENT_OVER_CURRENT }, }; -static struct tps6594_regulator_irq_type tps6594_ldo1_irq_types[] = { +static const struct tps6594_regulator_irq_type tps6594_ldo1_irq_types[] = { {TPS6594_IRQ_NAME_LDO1_OV ,"LDO1" ,"overvoltage" ,REGULATOR_EVENT_OVER_VOLTAGE_WARN }, {TPS6594_IRQ_NAME_LDO1_UV ,"LDO1" ,"undervoltage" ,REGULATOR_EVENT_UNDER_VOLTAGE }, {TPS6594_IRQ_NAME_LDO1_SC ,"LDO1" ,"short circuit" ,REGULATOR_EVENT_REGULATION_OUT },
@@ -310,7 +310,7 @@ static struct tps6594_regulator_irq_type tps6594_ldo1_irq_types[] = { REGULATOR_EVENT_OVER_CURRENT }, }; -static struct tps6594_regulator_irq_type tps6594_ldo2_irq_types[] = { +static const struct tps6594_regulator_irq_type tps6594_ldo2_irq_types[] = { {TPS6594_IRQ_NAME_LDO2_OV ,"LDO2" ,"overvoltage" ,REGULATOR_EVENT_OVER_VOLTAGE_WARN }, {TPS6594_IRQ_NAME_LDO2_UV ,"LDO2" ,"undervoltage" ,REGULATOR_EVENT_UNDER_VOLTAGE }, {TPS6594_IRQ_NAME_LDO2_SC ,"LDO2" ,"short circuit" ,REGULATOR_EVENT_REGULATION_OUT },
@@ -318,7 +318,7 @@ static struct tps6594_regulator_irq_type tps6594_ldo2_irq_types[] = { REGULATOR_EVENT_OVER_CURRENT }, }; -static struct tps6594_regulator_irq_type tps6594_ldo3_irq_types[] = { +static const struct tps6594_regulator_irq_type tps6594_ldo3_irq_types[] = { {TPS6594_IRQ_NAME_LDO3_OV ,"LDO3" ,"overvoltage" ,REGULATOR_EVENT_OVER_VOLTAGE_WARN }, {TPS6594_IRQ_NAME_LDO3_UV ,"LDO3" ,"undervoltage" ,REGULATOR_EVENT_UNDER_VOLTAGE }, {TPS6594_IRQ_NAME_LDO3_SC ,"LDO3" ,"short circuit" ,REGULATOR_EVENT_REGULATION_OUT },
@@ -326,7 +326,7 @@ static struct tps6594_regulator_irq_type tps6594_ldo3_irq_types[] = { REGULATOR_EVENT_OVER_CURRENT }, }; -static struct tps6594_regulator_irq_type tps6594_ldo4_irq_types[] = { +static const struct tps6594_regulator_irq_type tps6594_ldo4_irq_types[] = { {TPS6594_IRQ_NAME_LDO4_OV ,"LDO4" ,"overvoltage" ,REGULATOR_EVENT_OVER_VOLTAGE_WARN }, {TPS6594_IRQ_NAME_LDO4_UV ,"LDO4" ,"undervoltage" ,REGULATOR_EVENT_UNDER_VOLTAGE }, {TPS6594_IRQ_NAME_LDO4_SC ,"LDO4" ,"short circuit" ,REGULATOR_EVENT_REGULATION_OUT },
@@ -334,42 +334,42 @@ static struct tps6594_regulator_irq_type tps6594_ldo4_irq_types[] = { REGULATOR_EVENT_OVER_CURRENT }, }; -static struct tps6594_regulator_irq_type tps65224_buck1_irq_types[] = { +static const struct tps6594_regulator_irq_type tps65224_buck1_irq_types[] = { {TPS65224_IRQ_NAME_BUCK1_UVOV ,"BUCK1" ,"voltage out of range" ,REGULATOR_EVENT_REGULATION_OUT }, }; -static struct tps6594_regulator_irq_type tps65224_buck2_irq_types[] = { +static const struct tps6594_regulator_irq_type tps65224_buck2_irq_types[] = { {TPS65224_IRQ_NAME_BUCK2_UVOV ,"BUCK2" ,"voltage out of range" ,REGULATOR_EVENT_REGULATION_OUT }, }; -static struct tps6594_regulator_irq_type tps65224_buck3_irq_types[] = { +static const struct tps6594_regulator_irq_type tps65224_buck3_irq_types[] = { {TPS65224_IRQ_NAME_BUCK3_UVOV ,"BUCK3" ,"voltage out of range" ,REGULATOR_EVENT_REGULATION_OUT }, }; -static struct tps6594_regulator_irq_type tps65224_buck4_irq_types[] = { +static const struct tps6594_regulator_irq_type tps65224_buck4_irq_types[] = { {TPS65224_IRQ_NAME_BUCK4_UVOV ,"BUCK4" ,"voltage out of range" ,REGULATOR_EVENT_REGULATION_OUT }, }; -static struct tps6594_regulator_irq_type tps65224_ldo1_irq_types[] = { +static const struct tps6594_regulator_irq_type tps65224_ldo1_irq_types[] = { {TPS65224_IRQ_NAME_LDO1_UVOV ,"LDO1" ,"voltage out of range" ,REGULATOR_EVENT_REGULATION_OUT }, }; -static struct tps6594_regulator_irq_type tps65224_ldo2_irq_types[] = { +static const struct tps6594_regulator_irq_type tps65224_ldo2_irq_types[] = { {TPS65224_IRQ_NAME_LDO2_UVOV ,"LDO2" ,"voltage out of range" ,REGULATOR_EVENT_REGULATION_OUT }, }; -static struct tps6594_regulator_irq_type tps65224_ldo3_irq_types[] = { +static const struct tps6594_regulator_irq_type tps65224_ldo3_irq_types[] = { {TPS65224_IRQ_NAME_LDO3_UVOV ,"LDO3" ,"voltage out of range" ,REGULATOR_EVENT_REGULATION_OUT }, }; -static struct tps6594_regulator_irq_type *tps6594_bucks_irq_types[] = { +static const struct tps6594_regulator_irq_type *tps6594_bucks_irq_types[] = { tps6594_buck1_irq_types, tps6594_buck2_irq_types, tps6594_buck3_irq_types,
@@ -377,21 +377,21 @@ static struct tps6594_regulator_irq_type *tps6594_bucks_irq_types[] = { tps6594_buck5_irq_types, }; -static struct tps6594_regulator_irq_type *tps6594_ldos_irq_types[] = { +static const struct tps6594_regulator_irq_type *tps6594_ldos_irq_types[] = { tps6594_ldo1_irq_types, tps6594_ldo2_irq_types, tps6594_ldo3_irq_types, tps6594_ldo4_irq_types, }; -static struct tps6594_regulator_irq_type *tps65224_bucks_irq_types[] = { +static const struct tps6594_regulator_irq_type *tps65224_bucks_irq_types[] = { tps65224_buck1_irq_types, tps65224_buck2_irq_types, tps65224_buck3_irq_types, tps65224_buck4_irq_types, }; -static struct tps6594_regulator_irq_type *tps65224_ldos_irq_types[] = { +static const struct tps6594_regulator_irq_type *tps65224_ldos_irq_types[] = { tps65224_ldo1_irq_types, tps65224_ldo2_irq_types, tps65224_ldo3_irq_types,
@@ -516,11 +516,11 @@ static irqreturn_t tps6594_regulator_irq_handler(int irq, void *data)static int tps6594_request_reg_irqs (struct platform_device *pdev,struct regulator_dev *rdev,struct tps6594_regulator_irq_data *irq_data, -struct tps6594_regulator_irq_type *regs_irq_types, +const struct tps6594_regulator_irq_type *regs_irq_types,size_t interrupt_cnt,int *irq_idx) { -struct tps6594_regulator_irq_type *irq_type; +const struct tps6594_regulator_irq_type *irq_type;struct tps6594 *tps =dev_get_drvdata (pdev->dev.parent);size_t j;int irq;
@@ -558,8 +558,8 @@ static int tps6594_regulator_probe(struct platform_device *pdev)struct regulator_config config = {};struct tps6594_regulator_irq_data *irq_data;struct tps6594_ext_regulator_irq_data *irq_ext_reg_data; -struct tps6594_regulator_irq_type *irq_type; -struct tps6594_regulator_irq_type *irq_types; +const struct tps6594_regulator_irq_type *irq_type; +const struct tps6594_regulator_irq_type *irq_types;bool buck_configured[BUCK_NB ] = { false };bool buck_multi[MULTI_PHASE_NB ] = { false };
@@ -573,9 +573,9 @@ static int tps6594_regulator_probe(struct platform_device *pdev)unsigned int irq_count;unsigned int multi_phase_cnt;size_t reg_irq_nb; -struct tps6594_regulator_irq_type **bucks_irq_types; +const struct tps6594_regulator_irq_type **bucks_irq_types;const struct regulator_desc *multi_regs; -struct tps6594_regulator_irq_type **ldos_irq_types; +const struct tps6594_regulator_irq_type **ldos_irq_types;const struct regulator_desc *ldo_regs;size_t interrupt_count;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 369/1376 regulator: tps6594-regulator: remove interrupt_count
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Walle <[email protected]>
[ Upstream commit 16d1a9bf36ef649b1fdb866985b4b87584491fac ]
In .probe() interrupt_count and nr_types is essentially the same. It contains the number of different interrupt per LDO or buck converter. Drop one. This is a preparation patch to further simplify the handling of different variants of this PMIC.
This patch is only compile-time tested.
Stable-dep-of: 7fd28093b3ef ("regulator: tps6594: Fix device node reference leaks in multiphase loop")
--- drivers/regulator/tps6594-regulator.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-)
drivers/regulator/tps6594-regulator.c +6 -11
@@ -577,18 +577,15 @@ static int tps6594_regulator_probe(struct platform_device *pdev)const struct regulator_desc *multi_regs;const struct tps6594_regulator_irq_type **ldos_irq_types;const struct regulator_desc *ldo_regs; -size_t interrupt_count;if (tps->chip_id ==TPS65224 ) { bucks_irq_types = tps65224_bucks_irq_types; - interrupt_count =ARRAY_SIZE (tps65224_buck1_irq_types); multi_regs = tps65224_multi_regs; ldos_irq_types = tps65224_ldos_irq_types; ldo_regs = tps65224_ldo_regs; multi_phase_cnt =ARRAY_SIZE (tps65224_multi_regs); }else { bucks_irq_types = tps6594_bucks_irq_types; - interrupt_count =ARRAY_SIZE (tps6594_buck1_irq_types); multi_regs = tps6594_multi_regs; ldos_irq_types = tps6594_ldos_irq_types; ldo_regs = tps6594_ldo_regs;
@@ -686,29 +683,27 @@ static int tps6594_regulator_probe(struct platform_device *pdev) error =tps6594_request_reg_irqs (pdev, rdev, irq_data, bucks_irq_types[buck_idx], - interrupt_count, &irq_idx); + nr_types, &irq_idx);if (error)return error; error =tps6594_request_reg_irqs (pdev, rdev, irq_data, bucks_irq_types[buck_idx +1 ], - interrupt_count, &irq_idx); + nr_types, &irq_idx);if (error)return error;if (i ==MULTI_BUCK123 || i ==MULTI_BUCK1234 ) { error =tps6594_request_reg_irqs (pdev, rdev, irq_data, tps6594_bucks_irq_types[buck_idx +2 ], - interrupt_count, - &irq_idx); + nr_types, &irq_idx);if (error)return error; }if (i ==MULTI_BUCK1234 ) { error =tps6594_request_reg_irqs (pdev, rdev, irq_data, tps6594_bucks_irq_types[buck_idx +3 ], - interrupt_count, - &irq_idx); + nr_types, &irq_idx);if (error)return error; }
@@ -727,7 +722,7 @@ static int tps6594_regulator_probe(struct platform_device *pdev) "failed to register %s regulator\n", pdev->name); error =tps6594_request_reg_irqs (pdev, rdev, irq_data, - bucks_irq_types[i], interrupt_count, &irq_idx); + bucks_irq_types[i], nr_types, &irq_idx);if (error)return error; }
@@ -742,7 +737,7 @@ static int tps6594_regulator_probe(struct platform_device *pdev) pdev->name); error =tps6594_request_reg_irqs (pdev, rdev, irq_data, - ldos_irq_types[i], interrupt_count, + ldos_irq_types[i], nr_types, &irq_idx);if (error)return error;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 370/1376 regulator: tps6594-regulator: remove hardcoded buck config
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Walle <[email protected]>
[ Upstream commit 180a135eafa9e05657559bb04cc9eb6a86ca45f3 ]
Commit 00c826525fba ("regulator: tps6594-regulator: Add TI TPS65224 PMIC regulators") added support for the TPS65224 and made the description of the multi-phase buck converter variable depending on the variant of the PMIC. But this was just done for MUTLI_BUCK12 and MULTI_BUCK12_34 configs probably because this variant only supports a multi-phase configuration on buck 1 and 2. Remove the hardcoded value for the remaining two configs, too as future PMIC variants might also support these.
This is a preparation patch to refactor the regulator description and is compile-time only tested.
Stable-dep-of: 7fd28093b3ef ("regulator: tps6594: Fix device node reference leaks in multiphase loop")
--- drivers/regulator/tps6594-regulator.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/regulator/tps6594-regulator.c +2 -2
@@ -695,14 +695,14 @@ static int tps6594_regulator_probe(struct platform_device *pdev)if (i ==MULTI_BUCK123 || i ==MULTI_BUCK1234 ) { error =tps6594_request_reg_irqs (pdev, rdev, irq_data, - tps6594_bucks_irq_types[buck_idx +2 ], + bucks_irq_types[buck_idx +2 ], nr_types, &irq_idx);if (error)return error; }if (i ==MULTI_BUCK1234 ) { error =tps6594_request_reg_irqs (pdev, rdev, irq_data, - tps6594_bucks_irq_types[buck_idx +3 ], + bucks_irq_types[buck_idx +3 ], nr_types, &irq_idx);if (error)return error;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 371/1376 regulator: tps6594-regulator: refactor variant descriptions
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Walle <[email protected]>
[ Upstream commit e64ee27abfe1e9baea14b31c0a6b6bf93ac8652c ]
Instead of using conditionals or tri state operators throughout the .probe() provide a description per variant. This will make it much easier to add new variants later.
While at it, make the variable naming more consistent.
This patch is only compile-time tested.
Stable-dep-of: 7fd28093b3ef ("regulator: tps6594: Fix device node reference leaks in multiphase loop")
--- drivers/regulator/tps6594-regulator.c | 199 +++++++++++++++----------- 1 file changed, 112 insertions(+), 87 deletions(-)
drivers/regulator/tps6594-regulator.c +112 -87
@@ -21,10 +21,6 @@#define BUCK_NB 5#define LDO_NB 4#define MULTI_PHASE_NB 4 -/* TPS6593 and LP8764 supports OV, UV, SC, ILIM */ -#define REGS_INT_NB 4 -/* TPS65224 supports OV or UV */ -#define TPS65224_REGS_INT_NB 1enum tps6594_regulator_id {/* DCDC's */
@@ -192,7 +188,7 @@ static const struct regulator_ops tps6594_ldos_4_ops = { .map_voltage = regulator_map_voltage_linear_range, }; -static const struct regulator_desc buck_regs[] = { +static const struct regulator_desc tps6594_buck_regs[] = { TPS6594_REGULATOR("BUCK1", "buck1", TPS6594_BUCK_1, REGULATOR_VOLTAGE, tps6594_bucks_ops, TPS6594_MASK_BUCKS_VSET, TPS6594_REG_BUCKX_VOUT_1(0),
@@ -549,6 +545,63 @@ static int tps6594_request_reg_irqs(struct platform_device *pdev,return 0 ; } +struct tps6594_regulator_desc { +const struct regulator_desc *multi_phase_regs; +unsigned int num_multi_phase_regs; + +const struct regulator_desc *buck_regs; +int num_buck_regs; + +const struct regulator_desc *ldo_regs; +int num_ldo_regs; + +const struct tps6594_regulator_irq_type **bucks_irq_types; +const struct tps6594_regulator_irq_type **ldos_irq_types; +int num_irq_types; + +const struct tps6594_regulator_irq_type *ext_irq_types; +int num_ext_irqs; +}; + +static const struct tps6594_regulator_desc tps65224_reg_desc = { + .multi_phase_regs = tps65224_multi_regs, + .num_multi_phase_regs =ARRAY_SIZE (tps65224_multi_regs), + .buck_regs = tps65224_buck_regs, + .num_buck_regs =ARRAY_SIZE (tps65224_buck_regs), + .ldo_regs = tps65224_ldo_regs, + .num_ldo_regs =ARRAY_SIZE (tps65224_ldo_regs), + .bucks_irq_types = tps65224_bucks_irq_types, + .ldos_irq_types = tps65224_ldos_irq_types, + .num_irq_types =1 ,/* OV or UV */ + .ext_irq_types = tps65224_ext_regulator_irq_types, + .num_ext_irqs =ARRAY_SIZE (tps65224_ext_regulator_irq_types), +}; + +static const struct tps6594_regulator_desc tps6594_reg_desc = { + .multi_phase_regs = tps6594_multi_regs, + .num_multi_phase_regs =ARRAY_SIZE (tps6594_multi_regs), + .buck_regs = tps6594_buck_regs, + .num_buck_regs =ARRAY_SIZE (tps6594_buck_regs), + .ldo_regs = tps6594_ldo_regs, + .num_ldo_regs =ARRAY_SIZE (tps6594_ldo_regs), + .bucks_irq_types = tps6594_bucks_irq_types, + .ldos_irq_types = tps6594_ldos_irq_types, + .num_irq_types =4 ,/* OV, UV, SC and ILIM */ + .ext_irq_types = tps6594_ext_regulator_irq_types, + .num_ext_irqs =2 ,/* only VCCA OV and UV */ +}; + +static const struct tps6594_regulator_desc lp8764_reg_desc = { + .multi_phase_regs = tps6594_multi_regs, + .num_multi_phase_regs =ARRAY_SIZE (tps6594_multi_regs), + .buck_regs = tps6594_buck_regs, + .num_buck_regs =ARRAY_SIZE (tps6594_buck_regs), + .bucks_irq_types = tps6594_bucks_irq_types, + .num_irq_types =4 ,/* OV, UV, SC and ILIM */ + .ext_irq_types = tps6594_ext_regulator_irq_types, + .num_ext_irqs =ARRAY_SIZE (tps6594_ext_regulator_irq_types), +}; +static int tps6594_regulator_probe (struct platform_device *pdev) {struct tps6594 *tps =dev_get_drvdata (pdev->dev.parent);
@@ -559,38 +612,32 @@ static int tps6594_regulator_probe(struct platform_device *pdev)struct tps6594_regulator_irq_data *irq_data;struct tps6594_ext_regulator_irq_data *irq_ext_reg_data;const struct tps6594_regulator_irq_type *irq_type; -const struct tps6594_regulator_irq_type *irq_types;bool buck_configured[BUCK_NB ] = { false };bool buck_multi[MULTI_PHASE_NB ] = { false }; +const struct tps6594_regulator_desc *desc; +const struct regulator_desc *multi_regs;static const char *npname;int error, i, irq, multi;int irq_idx =0 ;int buck_idx =0 ; -int nr_ldo; -int nr_buck; -int nr_types; -unsigned int irq_count; -unsigned int multi_phase_cnt;size_t reg_irq_nb; -const struct tps6594_regulator_irq_type **bucks_irq_types; -const struct regulator_desc *multi_regs; -const struct tps6594_regulator_irq_type **ldos_irq_types; -const struct regulator_desc *ldo_regs; -if (tps->chip_id ==TPS65224 ) { - bucks_irq_types = tps65224_bucks_irq_types; - multi_regs = tps65224_multi_regs; - ldos_irq_types = tps65224_ldos_irq_types; - ldo_regs = tps65224_ldo_regs; - multi_phase_cnt =ARRAY_SIZE (tps65224_multi_regs); - }else { - bucks_irq_types = tps6594_bucks_irq_types; - multi_regs = tps6594_multi_regs; - ldos_irq_types = tps6594_ldos_irq_types; - ldo_regs = tps6594_ldo_regs; - multi_phase_cnt =ARRAY_SIZE (tps6594_multi_regs); - } +switch (tps->chip_id) { +case TPS65224 : + desc = &tps65224_reg_desc; +break ; +case TPS6594 : +case TPS6593 : + desc = &tps6594_reg_desc; +break ; +case LP8764 : + desc = &lp8764_reg_desc; +break ; +default : +dev_err (tps->dev,"unknown chip_id %lu\n" , tps->chip_id); +return -EINVAL ; + };enum {MULTI_BUCK12 ,
@@ -611,13 +658,14 @@ static int tps6594_regulator_probe(struct platform_device *pdev)* In case of Multiphase configuration, value should be defined for * buck_configured to avoid creating bucks for every buck in multiphase */ -for (multi =0 ; multi < multi_phase_cnt; multi++) { - np =of_find_node_by_name (tps->dev->of_node, multi_regs[multi].supply_name); +for (multi =0 ; multi < desc->num_multi_phase_regs; multi++) { + multi_regs = &desc->multi_phase_regs[multi]; + np =of_find_node_by_name (tps->dev->of_node, multi_regs->supply_name); npname =of_node_full_name (np); np_pmic_parent =of_get_parent (of_get_parent (np));if (of_node_cmp (of_node_full_name (np_pmic_parent), tps->dev->of_node->full_name))continue ; -if (strcmp (npname, multi_regs[multi].supply_name) ==0 ) { +if (strcmp (npname, multi_regs->supply_name) ==0 ) {switch (multi) {case MULTI_BUCK12 : buck_multi[0 ] = true;
@@ -650,28 +698,19 @@ static int tps6594_regulator_probe(struct platform_device *pdev) } } -if (tps->chip_id ==TPS65224 ) { - nr_buck =ARRAY_SIZE (tps65224_buck_regs); - nr_ldo =ARRAY_SIZE (tps65224_ldo_regs); - nr_types =TPS65224_REGS_INT_NB ; - }else { - nr_buck =ARRAY_SIZE (buck_regs); - nr_ldo = (tps->chip_id ==LP8764 ) ?0 :ARRAY_SIZE (tps6594_ldo_regs); - nr_types =REGS_INT_NB ; - } - - reg_irq_nb = nr_types * (nr_buck + nr_ldo); + reg_irq_nb = desc->num_irq_types * (desc->num_buck_regs + desc->num_ldo_regs); irq_data =devm_kmalloc_array (tps->dev, reg_irq_nb,sizeof (struct tps6594_regulator_irq_data ),GFP_KERNEL );if (!irq_data)return -ENOMEM ; -for (i =0 ; i < multi_phase_cnt; i++) { +for (i =0 ; i < desc->num_multi_phase_regs; i++) {if (!buck_multi[i])continue ; - rdev =devm_regulator_register (&pdev->dev, &multi_regs[i], &config); + rdev =devm_regulator_register (&pdev->dev, &desc->multi_phase_regs[i], + &config);if (IS_ERR (rdev)) return dev_err_probe(tps->dev, PTR_ERR(rdev), "failed to register %s regulator\n",
@@ -682,89 +721,74 @@ static int tps6594_regulator_probe(struct platform_device *pdev) buck_idx =2 ; error =tps6594_request_reg_irqs (pdev, rdev, irq_data, - bucks_irq_types[buck_idx], - nr_types, &irq_idx); + desc->bucks_irq_types[buck_idx], + desc->num_irq_types, &irq_idx);if (error)return error; error =tps6594_request_reg_irqs (pdev, rdev, irq_data, - bucks_irq_types[buck_idx +1 ], - nr_types, &irq_idx); + desc->bucks_irq_types[buck_idx +1 ], + desc->num_irq_types, &irq_idx);if (error)return error;if (i ==MULTI_BUCK123 || i ==MULTI_BUCK1234 ) { error =tps6594_request_reg_irqs (pdev, rdev, irq_data, - bucks_irq_types[buck_idx +2 ], - nr_types, &irq_idx); + desc->bucks_irq_types[buck_idx +2 ], + desc->num_irq_types, + &irq_idx);if (error)return error; }if (i ==MULTI_BUCK1234 ) { error =tps6594_request_reg_irqs (pdev, rdev, irq_data, - bucks_irq_types[buck_idx +3 ], - nr_types, &irq_idx); + desc->bucks_irq_types[buck_idx +3 ], + desc->num_irq_types, + &irq_idx);if (error)return error; } } -for (i =0 ; i < nr_buck; i++) { +for (i =0 ; i < desc->num_buck_regs; i++) {if (buck_configured[i])continue ; -const struct regulator_desc *buck_cfg = (tps->chip_id ==TPS65224 ) ? - tps65224_buck_regs : buck_regs; - - rdev =devm_regulator_register (&pdev->dev, &buck_cfg[i], &config); + rdev =devm_regulator_register (&pdev->dev, &desc->buck_regs[i], &config);if (IS_ERR (rdev))return dev_err_probe (tps->dev,PTR_ERR (rdev),"failed to register %s regulator\n" , pdev->name); error =tps6594_request_reg_irqs (pdev, rdev, irq_data, - bucks_irq_types[i], nr_types, &irq_idx); + desc->bucks_irq_types[i], + desc->num_irq_types, &irq_idx);if (error)return error; } -/* LP8764 doesn't have LDO */ -if (tps->chip_id !=LP8764 ) { -for (i =0 ; i < nr_ldo; i++) { - rdev =devm_regulator_register (&pdev->dev, &ldo_regs[i], &config); -if (IS_ERR (rdev)) -return dev_err_probe (tps->dev,PTR_ERR (rdev), -"failed to register %s regulator\n" , - pdev->name); - - error =tps6594_request_reg_irqs (pdev, rdev, irq_data, - ldos_irq_types[i], nr_types, - &irq_idx); -if (error) -return error; - } - } +for (i =0 ; i < desc->num_ldo_regs; i++) { + rdev =devm_regulator_register (&pdev->dev, &desc->ldo_regs[i], &config); +if (IS_ERR (rdev)) +return dev_err_probe (tps->dev,PTR_ERR (rdev), +"failed to register %s regulator\n" , + pdev->name); -if (tps->chip_id ==TPS65224 ) { - irq_types = tps65224_ext_regulator_irq_types; - irq_count =ARRAY_SIZE (tps65224_ext_regulator_irq_types); - }else { - irq_types = tps6594_ext_regulator_irq_types; -if (tps->chip_id ==LP8764 ) - irq_count =ARRAY_SIZE (tps6594_ext_regulator_irq_types); -else -/* TPS6593 supports only VCCA OV and UV */ - irq_count =2 ; + error =tps6594_request_reg_irqs (pdev, rdev, irq_data, + desc->ldos_irq_types[i], + desc->num_irq_types, &irq_idx); +if (error) +return error; } irq_ext_reg_data =devm_kmalloc_array (tps->dev, - irq_count, + desc->num_ext_irqs,sizeof (struct tps6594_ext_regulator_irq_data ),GFP_KERNEL );if (!irq_ext_reg_data)return -ENOMEM ; -for (i =0 ; i < irq_count; ++i) { - irq_type = &irq_types[i]; +for (i =0 ; i < desc->num_ext_irqs; ++i) { + irq_type = &desc->ext_irq_types[i]; irq =platform_get_irq_byname (pdev, irq_type->irq_name);if (irq <0 )return -EINVAL ;
@@ -782,6 +806,7 @@ static int tps6594_regulator_probe(struct platform_device *pdev)"failed to request %s IRQ %d\n" , irq_type->irq_name, irq); } +return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 372/1376 regulator: tps6594: Fix device node reference leaks in multiphase loop
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uday Khare <[email protected]>
[ Upstream commit 7fd28093b3effc4f92566466df364622830ec608 ]
In tps6594_regulator_probe(), the multi-phase configuration loop calls of_find_node_by_name() to find buck nodes by name, and of_get_parent() twice to navigate to the PMIC parent node. None of the acquired node references (np, intermediate parent, np_pmic_parent) are ever released via of_node_put(), causing a reference leak on every loop iteration.
Additionally, of_find_node_by_name() can return NULL, but the result was immediately passed to of_node_full_name() and of_get_parent() without a NULL check, which could lead to a NULL pointer dereference.
Fix this by:
- Adding a NULL check for np after of_find_node_by_name()
- Storing the intermediate parent node in a local variable np_parent
- Calling of_node_put() on np, np_parent and np_pmic_parent at the end of each loop iteration
--- drivers/regulator/tps6594-regulator.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-)
drivers/regulator/tps6594-regulator.c +15 -4
@@ -659,13 +659,20 @@ static int tps6594_regulator_probe(struct platform_device *pdev)* buck_configured to avoid creating bucks for every buck in multiphase */ for (multi =0 ; multi < desc->num_multi_phase_regs; multi++) { +struct device_node *np_parent; + multi_regs = &desc->multi_phase_regs[multi]; np =of_find_node_by_name (tps->dev->of_node, multi_regs->supply_name); - npname =of_node_full_name (np); - np_pmic_parent =of_get_parent (of_get_parent (np)); -if (of_node_cmp (of_node_full_name (np_pmic_parent), tps->dev->of_node->full_name)) +if (!np)continue ; -if (strcmp (npname, multi_regs->supply_name) ==0 ) { + + npname =of_node_full_name (np); + np_parent =of_get_parent (np); + np_pmic_parent =of_get_parent (np_parent); + +if (np_pmic_parent && + !of_node_cmp (of_node_full_name (np_pmic_parent), tps->dev->of_node->full_name) && +strcmp (npname, multi_regs->supply_name) ==0 ) {switch (multi) {case MULTI_BUCK12 : buck_multi[0 ] = true;
@@ -696,6 +703,10 @@ static int tps6594_regulator_probe(struct platform_device *pdev)break ; } } + +of_node_put (np_pmic_parent); +of_node_put (np_parent); +of_node_put (np); } reg_irq_nb = desc->num_irq_types * (desc->num_buck_regs + desc->num_ldo_regs);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 373/1376 drm/amdgpu/pm/powerplay: bounds-check voltage index in SMU7 lookup
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Asad Kamal <[email protected]>
[ Upstream commit 3a8a05477cda6c8293e2b629495b42981dcaba32 ]
vddInd and vddcInd fields from VBIOS-parsed tables are used to index into voltage lookup tables without a bounds check. Return -EINVAL when any index is out of range.
--- .../drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+)
drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +24 -0
@@ -2216,12 +2216,24 @@ static int smu7_patch_voltage_dependency_tables_with_lookup_table(if (data->vdd_gfx_control ==SMU7_VOLTAGE_CONTROL_BY_SVID2 ) {for (entry_id =0 ; entry_id < sclk_table->count; ++entry_id) { voltage_id = sclk_table->entries[entry_id].vddInd; +if (voltage_id >= table_info->vddgfx_lookup_table->count) { +pr_err ("amdgpu: sclk[%u] vddgfx index %u out of bounds (%u)\n" , + entry_id, voltage_id, + table_info->vddgfx_lookup_table->count); +return -EINVAL ; + } sclk_table->entries[entry_id].vddgfx = table_info->vddgfx_lookup_table->entries[voltage_id].us_vdd; } }else {for (entry_id =0 ; entry_id < sclk_table->count; ++entry_id) { voltage_id = sclk_table->entries[entry_id].vddInd; +if (voltage_id >= table_info->vddc_lookup_table->count) { +pr_err ("amdgpu: sclk[%u] vddc index %u out of bounds (%u)\n" , + entry_id, voltage_id, + table_info->vddc_lookup_table->count); +return -EINVAL ; + } sclk_table->entries[entry_id].vddc = table_info->vddc_lookup_table->entries[voltage_id].us_vdd; }
@@ -2229,12 +2241,24 @@ static int smu7_patch_voltage_dependency_tables_with_lookup_table(for (entry_id =0 ; entry_id < mclk_table->count; ++entry_id) { voltage_id = mclk_table->entries[entry_id].vddInd; +if (voltage_id >= table_info->vddc_lookup_table->count) { +pr_err ("amdgpu: mclk[%u] vddc index %u out of bounds (%u)\n" , + entry_id, voltage_id, + table_info->vddc_lookup_table->count); +return -EINVAL ; + } mclk_table->entries[entry_id].vddc = table_info->vddc_lookup_table->entries[voltage_id].us_vdd; }for (entry_id =0 ; entry_id < mm_table->count; ++entry_id) { voltage_id = mm_table->entries[entry_id].vddcInd; +if (voltage_id >= table_info->vddc_lookup_table->count) { +pr_err ("amdgpu: mm[%u] vddc index %u out of bounds (%u)\n" , + entry_id, voltage_id, + table_info->vddc_lookup_table->count); +return -EINVAL ; + } mm_table->entries[entry_id].vddc = table_info->vddc_lookup_table->entries[voltage_id].us_vdd; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 374/1376 drm/amdgpu/pm/powerplay: bounds-check voltage index in Vega10 lookup
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Asad Kamal <[email protected]>
[ Upstream commit 6fa33f594e46e775a94097f71b486d7b006b6917 ]
vddInd, vddciInd and mvddInd from VBIOS-parsed tables index into vddc, vddci and vddmem lookup tables without bounds checks across nine sites. Return -EINVAL when any index is out of range.
--- .../drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c +34 -1
@@ -685,10 +685,18 @@ static int vega10_patch_voltage_dependency_tables_with_lookup_table(case 3 : vdt = table_info->vdd_dep_on_pixclk;break ;case 4 : vdt = table_info->vdd_dep_on_dispclk;break ;case 5 : vdt = table_info->vdd_dep_on_phyclk;break ; +default : +continue ; }for (entry_id =0 ; entry_id < vdt->count; entry_id++) { voltage_id = vdt->entries[entry_id].vddInd; +if (voltage_id >= table_info->vddc_lookup_table->count) { +pr_err ("amdgpu: clk_dep[%u][%u] vddc index %u out of bounds (%u)\n" , + i, entry_id, voltage_id, + table_info->vddc_lookup_table->count); +return -EINVAL ; + } vdt->entries[entry_id].vddc = table_info->vddc_lookup_table->entries[voltage_id].us_vdd; }
@@ -696,23 +704,48 @@ static int vega10_patch_voltage_dependency_tables_with_lookup_table(for (entry_id =0 ; entry_id < mm_table->count; ++entry_id) { voltage_id = mm_table->entries[entry_id].vddcInd; +if (voltage_id >= table_info->vddc_lookup_table->count) { +pr_err ("amdgpu: mm[%u] vddc index %u out of bounds (%u)\n" , + entry_id, voltage_id, + table_info->vddc_lookup_table->count); +return -EINVAL ; + } mm_table->entries[entry_id].vddc = table_info->vddc_lookup_table->entries[voltage_id].us_vdd; }for (entry_id =0 ; entry_id < mclk_table->count; ++entry_id) { voltage_id = mclk_table->entries[entry_id].vddInd; +if (voltage_id >= table_info->vddc_lookup_table->count) { +pr_err ("amdgpu: mclk[%u] vddc index %u out of bounds (%u)\n" , + entry_id, voltage_id, + table_info->vddc_lookup_table->count); +return -EINVAL ; + } mclk_table->entries[entry_id].vddc = table_info->vddc_lookup_table->entries[voltage_id].us_vdd; + voltage_id = mclk_table->entries[entry_id].vddciInd; +if (voltage_id >= table_info->vddci_lookup_table->count) { +pr_err ("amdgpu: mclk[%u] vddci index %u out of bounds (%u)\n" , + entry_id, voltage_id, + table_info->vddci_lookup_table->count); +return -EINVAL ; + } mclk_table->entries[entry_id].vddci = table_info->vddci_lookup_table->entries[voltage_id].us_vdd; + voltage_id = mclk_table->entries[entry_id].mvddInd; +if (voltage_id >= table_info->vddmem_lookup_table->count) { +pr_err ("amdgpu: mclk[%u] vddmem index %u out of bounds (%u)\n" , + entry_id, voltage_id, + table_info->vddmem_lookup_table->count); +return -EINVAL ; + } mclk_table->entries[entry_id].mvdd = table_info->vddmem_lookup_table->entries[voltage_id].us_vdd; } -return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 375/1376 tools/bpf/bpftool: Reset vmlinux BTF after map commands
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yichong Chen <[email protected]>
[ Upstream commit 66d7e39e49b0dd57610c9b63afc65b4d5690983b ]
get_map_kv_btf() caches the vmlinux BTF object when a map uses btf_vmlinux_value_type_id. map dump released that object when the command completed, but left the global pointer stale.
The same cached object can also be returned to print_key_value(), which freed it directly. That leaves btf_vmlinux dangling before the command cleanup path runs.
Use free_map_kv_btf() for per-entry cleanup, and reset the cached btf_vmlinux pointer when the map command releases the object. This keeps batch mode from reusing a freed BTF object.
--- tools/bpf/bpftool/map.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
tools/bpf/bpftool/map.c +9 -3
@@ -787,6 +787,12 @@ static int maps_have_btf(int *fds, int nb_fds)static struct btf *btf_vmlinux; +static void free_btf_vmlinux (void ) +{ +btf__free (btf_vmlinux); + btf_vmlinux =NULL ; +} +static int get_map_kv_btf (const struct bpf_map_info *info,struct btf **btf) {int err =0 ;
@@ -955,7 +961,7 @@ static int do_dump(int argc, char **argv)close (fds[i]); exit_free:free (fds); -btf__free (btf_vmlinux); +free_btf_vmlinux ();return err; }
@@ -1046,7 +1052,7 @@ static void print_key_value(struct bpf_map_info *info, void *key, btf_wtr =get_btf_writer ();if (!btf_wtr) {p_info ("failed to create json writer for btf. falling back to plain output" ); -btf__free (btf); +free_map_kv_btf (btf); btf =NULL ;print_entry_plain (info, key, value); }else {
@@ -1062,7 +1068,7 @@ static void print_key_value(struct bpf_map_info *info, void *key, }else {print_entry_plain (info, key, value); } -btf__free (btf); +free_map_kv_btf (btf); }static int do_lookup (int argc,char **argv)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 376/1376 tools/bpf/bpftool: Reset vmlinux BTF after struct_ops commands
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yichong Chen <[email protected]>
[ Upstream commit f7f540e19751face50c68bb9ce58460fcb46c293 ]
struct_ops frees the global btf_vmlinux object.
In batch mode, a later struct_ops command can reuse stale state.
Reset the BTF pointer and cached map info state.
--- tools/bpf/bpftool/struct_ops.c | 4 ++++ 1 file changed, 4 insertions(+)
tools/bpf/bpftool/struct_ops.c +4 -0
@@ -643,6 +643,10 @@ int do_struct_ops(int argc, char **argv) err =cmd_select (cmds, argc, argv, do_help);btf__free (btf_vmlinux); + btf_vmlinux =NULL ; + map_info_type =NULL ; + map_info_alloc_len =0 ; + map_info_type_id =0 ;return err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 377/1376 bpf: Copy per-CPU map value padding in copy_map_value_long()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Hwang <[email protected]>
[ Upstream commit 7cf9cd98cf6f0df3befc167ca6b54c07014d71de ]
In kernel, per-CPU map elements are stored with round_up(map->value_size, 8) bytes. On UAPI lookup paths, it copies the rounded size for each CPU into a temporary buffer.
However, copy_map_value_long() passes 'map->value_size' to bpf_obj_memcpy(). When the map has special fields, bpf_obj_memcpy() copies around those fields with memcpy(), and does not copy the tail padding between 'map->value_size' and round_up(map->value_size, 8).
The temporary UAPI lookup buffers are allocated without __GFP_ZERO. As a result, when the per-CPU map's value size is not equal to round_up(map->value_size, 8), UAPI LOOKUP_ELEM and its variants can return stale heap contents from that padding to user space. The same issue applies to bpf_iter for per-CPU maps.
Pass round_up(map->value_size, 8) to bpf_obj_memcpy() from copy_map_value_long(), so per-CPU maps both with and without special fields copy the entire per-CPU slot. Remove the now redundant round_up() from bpf_obj_memcpy()'s long_memcpy path.
--- include/linux/bpf.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
include/linux/bpf.h +2 -2
@@ -500,7 +500,7 @@ static inline void bpf_obj_memcpy(struct btf_record *rec,if (IS_ERR_OR_NULL (rec)) {if (long_memcpy) -bpf_long_memcpy (dst, src,round_up (size,8 )); +bpf_long_memcpy (dst, src, size);else memcpy (dst, src, size);return ;
@@ -523,7 +523,7 @@ static inline void copy_map_value(struct bpf_map *map, void *dst, void *src)static inline void copy_map_value_long (struct bpf_map *map,void *dst,void *src) { -bpf_obj_memcpy (map->record, dst, src, map->value_size, true); +bpf_obj_memcpy (map->record, dst, src,round_up (map->value_size,8 ), true); }static inline void bpf_obj_memzero (struct btf_record *rec,void *dst,u32 size)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 378/1376 selftests/bpf: Systematically add SO_REUSEADDR in start_server_addr
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexis Lothoré (eBPF Foundation) <[email protected]>
[ Upstream commit 38e36514fcb01ff1cce84cd77a93906f233a4cb8 ]
Some tests have to stop/start a server multiple time with the same listening address. Doing so without SO_REUSADDR leads to failures due to the socket still being in TIME_WAIT right after the first instance stop/before the second instance start. Instead of letting each test manually set SO_REUSEADDR on their servers, it can be done automatically by start_server_addr for all tests (and without any major downside).
Enforce SO_REUSEADDR in start_server_addr for all tests.
Stable-dep-of: b4b8b334f6b5 ("selftests/bpf: Mask socket type flags in mptcpify prog")
--- tools/testing/selftests/bpf/network_helpers.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
tools/testing/selftests/bpf/network_helpers.c +7 -1
@@ -97,7 +97,7 @@ int settimeo(int fd, int timeout_ms)int start_server_addr (int type,const struct sockaddr_storage *addr,socklen_t addrlen,const struct network_helper_opts *opts) { -int fd; +int on =1 , fd;if (!opts) opts = &default_opts;
@@ -111,6 +111,12 @@ int start_server_addr(int type, const struct sockaddr_storage *addr, socklen_t aif (settimeo (fd, opts->timeout_ms)) goto error_close; +if (type ==SOCK_STREAM && +setsockopt (fd,SOL_SOCKET ,SO_REUSEADDR , &on,sizeof (on))) { +log_err ("Failed to enable SO_REUSEADDR" ); + goto error_close; + } +if (opts->post_socket_cb && opts->post_socket_cb (fd, opts->cb_opts)) {log_err ("Failed to call post_socket_cb" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 379/1376 selftests/bpf: Mask socket type flags in mptcpify prog
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guillaume Maudoux <[email protected]>
[ Upstream commit b4b8b334f6b535a86ab83f18d3d241fe01270bc3 ]
The mptcpify BPF prog upgrades eligible TCP sockets to MPTCP, but only when the socket type is exactly SOCK_STREAM. Its update_socket_protocol() hook runs on the raw type from userspace, before the socket core masks it with SOCK_TYPE_MASK, so the type may still carry SOCK_CLOEXEC or SOCK_NONBLOCK in its upper bits and the equality check fails.
As a result, a socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0) -- what common libraries do by default -- is silently left as plain TCP. This was hit in practice with curl. Since mptcpify.c is referenced as example code for enabling MPTCP transparently, the same mistake is likely to be copied into real deployments where it fails the same way and is hard to diagnose.
Mask the type before comparing, mirroring the socket core. Extend the test to also create the server with SOCK_CLOEXEC set; the same masking is applied to start_server_addr() so a flagged type still listens.
--- tools/testing/selftests/bpf/network_helpers.c | 4 ++-- tools/testing/selftests/bpf/network_helpers.h | 5 +++++ tools/testing/selftests/bpf/prog_tests/mptcp.c | 13 ++++++++++--- tools/testing/selftests/bpf/progs/bpf_tracing_net.h | 3 +++ tools/testing/selftests/bpf/progs/mptcpify.c | 2 +- 5 files changed, 21 insertions(+), 6 deletions(-)
tools/testing/selftests/bpf/network_helpers.c +2 -2
@@ -111,7 +111,7 @@ int start_server_addr(int type, const struct sockaddr_storage *addr, socklen_t aif (settimeo (fd, opts->timeout_ms)) goto error_close; -if (type ==SOCK_STREAM && +if ((type &SOCK_TYPE_MASK ) ==SOCK_STREAM &&setsockopt (fd,SOL_SOCKET ,SO_REUSEADDR , &on,sizeof (on))) {log_err ("Failed to enable SO_REUSEADDR" ); goto error_close;
@@ -128,7 +128,7 @@ int start_server_addr(int type, const struct sockaddr_storage *addr, socklen_t a goto error_close; } -if (type ==SOCK_STREAM ) { +if ((type &SOCK_TYPE_MASK ) ==SOCK_STREAM ) {if (listen (fd, opts->backlog ?MAX (opts->backlog,0 ) :1 ) <0 ) {log_err ("Failed to listed on socket" ); goto error_close;
tools/testing/selftests/bpf/network_helpers.h +5 -0
@@ -22,6 +22,11 @@ typedef __u16 __sum16;#define VIP_NUM 5#define MAGIC_BYTES 123 +/* include/linux/net.h */ +#ifndef SOCK_TYPE_MASK +#define SOCK_TYPE_MASK 0xf +#endif +struct network_helper_opts {int timeout_ms;int proto;
tools/testing/selftests/bpf/prog_tests/mptcp.c +10 -3
@@ -275,7 +275,7 @@ static int verify_mptcpify(int server_fd, int client_fd)return err; } -static int run_mptcpify (int cgroup_fd) +static int run_mptcpify (int cgroup_fd,int type) {int server_fd, client_fd, err =0 ;struct mptcpify *mptcpify_skel;
@@ -291,7 +291,7 @@ static int run_mptcpify(int cgroup_fd) goto out;/* without MPTCP */ - server_fd =start_server (AF_INET ,SOCK_STREAM ,NULL ,0 ,0 ); + server_fd =start_server (AF_INET , type,NULL ,0 ,0 );if (!ASSERT_GE (server_fd,0 ,"start_server" )) { err = -EIO ; goto out;
@@ -328,7 +328,14 @@ static void test_mptcpify(void)if (!ASSERT_OK_PTR (nstoken,"create_netns" )) goto fail; -ASSERT_OK (run_mptcpify (cgroup_fd),"run_mptcpify" ); +ASSERT_OK (run_mptcpify (cgroup_fd,SOCK_STREAM ),"run_mptcpify" ); +/* userspace sets flags such as SOCK_CLOEXEC together with the type; +* the BPF prog must still upgrade the socket to MPTCP. See +* update_socket_protocol() in net/socket.c, which runs before the +* type is masked with SOCK_TYPE_MASK. +*/ +ASSERT_OK (run_mptcpify (cgroup_fd,SOCK_STREAM |SOCK_CLOEXEC ), +"run_mptcpify_cloexec" ); fail:cleanup_netns (nstoken);
tools/testing/selftests/bpf/progs/bpf_tracing_net.h +3 -0
@@ -8,6 +8,9 @@#define AF_INET 2#define AF_INET6 10 +/* include/linux/net.h */ +#define SOCK_TYPE_MASK 0xf +#define SOL_SOCKET 1#define SO_REUSEADDR 2#define SO_SNDBUF 7
tools/testing/selftests/bpf/progs/mptcpify.c +1 -1
@@ -15,7 +15,7 @@ int BPF_PROG(mptcpify, int family, int type, int protocol)return protocol;if ((family ==AF_INET || family ==AF_INET6 ) && - type ==SOCK_STREAM && + (type &SOCK_TYPE_MASK ) ==SOCK_STREAM && (!protocol || protocol ==IPPROTO_TCP )) {return IPPROTO_MPTCP ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 380/1376 bpf,lsm: Drop bpf_prog_free from sleepable_lsm_hooks
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sechang Lim <[email protected]>
[ Upstream commit 2ce3f548cfc6a1fe4c53479cf8a21931cdfd51d8 ]
__bpf_prog_put_rcu() is the call_rcu() callback for non-sleepable programs. security_bpf_prog_free() called from there fires bpf_prog_free in softirq; if a sleepable LSM prog is attached to that hook, might_fault() BUGs:
BUG: sleeping function called from invalid context in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 5038 preempt_count: 101, expected: 0 Call Trace: <IRQ> __bpf_prog_enter_sleepable+0x1cd/0x320 kernel/bpf/trampoline.c:1255 bpf_trampoline_6442549705+0x53/0xd7 security_bpf_prog_free+0xde/0x130 security/security.c:5465 __bpf_prog_put_rcu+0xab/0xd0 kernel/bpf/syscall.c:2365 rcu_do_batch kernel/rcu/tree.c:2617 [inline] handle_softirqs+0x236/0x800 kernel/softirq.c:622 </IRQ>
The call_rcu/call_rcu_tasks_trace split reflects the freed program's sleepability, not that of any attached observer.
security_bpf_prog_free() also frees prog->aux->security, which has to stay after the grace period, so drop bpf_prog_free from sleepable_lsm_hooks rather than move the call. Non-sleepable observers still run there.
--- kernel/bpf/bpf_lsm.c | 1 - 1 file changed, 1 deletion(-)
kernel/bpf/bpf_lsm.c +0 -1
@@ -293,7 +293,6 @@ BTF_ID(func, bpf_lsm_bpf_map_create) BTF_ID(func, bpf_lsm_bpf_map_free) BTF_ID(func, bpf_lsm_bpf_prog) BTF_ID(func, bpf_lsm_bpf_prog_load) -BTF_ID(func, bpf_lsm_bpf_prog_free) BTF_ID(func, bpf_lsm_bpf_token_create) BTF_ID(func, bpf_lsm_bpf_token_free)BTF_ID (func, bpf_lsm_bpf_token_cmd)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 381/1376 mm: add build-time option for hotplug memory default online type
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gregory Price <[email protected]>
[ Upstream commit 44d46b76c3a4b514a0cc9dab147ed430e5c1d699 ]
Memory hotplug presently auto-onlines memory into a zone the kernel deems appropriate if CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE=y.
The memhp_default_state boot param enables runtime config, but it's not possible to do this at build-time.
Remove CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE, and replace it with CONFIG_MHP_DEFAULT_ONLINE_TYPE_* choices that sync with the boot param.
Selections:
CONFIG_MHP_DEFAULT_ONLINE_TYPE_OFFLINE
=> mhp_default_online_type = "offline"
Memory will not be onlined automatically.
CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_AUTO
=> mhp_default_online_type = "online"
Memory will be onlined automatically in a zone deemed. appropriate by the kernel.
CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_KERNEL
=> mhp_default_online_type = "online_kernel"
Memory will be onlined automatically.
The zone may allow kernel data (e.g. ZONE_NORMAL).
CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_MOVABLE
=> mhp_default_online_type = "online_movable"
Memory will be onlined automatically.
The zone will be ZONE_MOVABLE.
Default to CONFIG_MHP_DEFAULT_ONLINE_TYPE_OFFLINE to match the existing default CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE=n behavior.
Existing users of CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE=y should use CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_AUTO.
Stable-dep-of: 2ebce860bdd7 ("mm/mm_init: handle alloc_percpu failure in free_area_init_core_hotplug")
--- .../admin-guide/kernel-parameters.txt | 4 +- .../admin-guide/mm/memory-hotplug.rst | 4 +- arch/loongarch/configs/loongson3_defconfig | 5 +- drivers/base/memory.c | 4 +- include/linux/memory_hotplug.h | 5 +- mm/Kconfig | 57 ++++++++++++++++--- mm/memory_hotplug.c | 33 ++++++++--- 7 files changed, 89 insertions(+), 23 deletions(-)
Documentation/admin-guide/kernel-parameters.txt +2 -2
@@ -3362,8 +3362,8 @@ [KNL] Set the initial state for the memory hotplug onlining policy. If not specified, the default value is set according to the - CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE kernel config - option. + CONFIG_MHP_DEFAULT_ONLINE_TYPE kernel config + options. See Documentation/admin-guide/mm/memory-hotplug.rst. memmap=exactmap [KNL,X86,EARLY] Enable setting of an exact
Documentation/admin-guide/mm/memory-hotplug.rst +2 -2
@@ -280,8 +280,8 @@ The following files are currently defined: blocks; configure auto-onlining. The default value depends on the - CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE kernel configuration - option. + CONFIG_MHP_DEFAULT_ONLINE_TYPE kernel configuration + options. See the ``state`` property of memory blocks for details. ``block_size_bytes`` read-only: the size in bytes of a memory block.
arch/loongarch/configs/loongson3_defconfig +4 -1
@@ -99,7 +99,10 @@ CONFIG_ZBUD=y CONFIG_ZSMALLOC=m # CONFIG_COMPAT_BRK is not set CONFIG_MEMORY_HOTPLUG=y -CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE=y +# CONFIG_MHP_DEFAULT_ONLINE_TYPE_OFFLINE is not set +CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_AUTO=y +# CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_KERNEL is not set +# CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_MOVABLE is not set CONFIG_MEMORY_HOTREMOVE=y CONFIG_KSM=y CONFIG_TRANSPARENT_HUGEPAGE=y
drivers/base/memory.c +2 -2
@@ -512,7 +512,7 @@ static ssize_t auto_online_blocks_show(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "%s\n", -online_type_to_str [mhp_default_online_type]); +online_type_to_str [mhp_get_default_online_type ()]); } static ssize_t auto_online_blocks_store(struct device *dev,
@@ -524,7 +524,7 @@ static ssize_t auto_online_blocks_store(struct device *dev,if (online_type <0 )return -EINVAL ; - mhp_default_online_type = online_type; +mhp_set_default_online_type (online_type);return count; }
include/linux/memory_hotplug.h +3 -2
@@ -144,8 +144,6 @@ extern u64 max_mem_size;extern int mhp_online_type_from_str (const char *str); -/* Default online_type (MMOP_*) when new memory blocks are added. */ -extern int mhp_default_online_type;/* If movable_node boot option specified */ extern bool movable_node_enabled;static inline bool movable_node_is_enabled (void )
@@ -304,6 +302,9 @@ static inline void __remove_memory(u64 start, u64 size) {}#endif /* CONFIG_MEMORY_HOTREMOVE */ #ifdef CONFIG_MEMORY_HOTPLUG +/* Default online_type (MMOP_*) when new memory blocks are added. */ +extern int mhp_get_default_online_type (void ); +extern void mhp_set_default_online_type (int online_type);extern void __ref free_area_init_core_hotplug (struct pglist_data *pgdat);extern int __add_memory (int nid,u64 start,u64 size,mhp_t mhp_flags);extern int add_memory (int nid,u64 start,u64 size,mhp_t mhp_flags);
mm/Kconfig +50 -7
70 lines not on this page · raw message
mm/memory_hotplug.c +26 -7
@@ -219,11 +219,30 @@ void put_online_mems(void)bool movable_node_enabled = false; -#ifndef CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE -int mhp_default_online_type =MMOP_OFFLINE ; -#else -int mhp_default_online_type =MMOP_ONLINE ; -#endif +static int mhp_default_online_type =-1 ; +int mhp_get_default_online_type (void ) +{ +if (mhp_default_online_type >=0 ) +return mhp_default_online_type; + +if (IS_ENABLED (CONFIG_MHP_DEFAULT_ONLINE_TYPE_OFFLINE )) + mhp_default_online_type =MMOP_OFFLINE ; +else if (IS_ENABLED (CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_AUTO )) + mhp_default_online_type =MMOP_ONLINE ; +else if (IS_ENABLED (CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_KERNEL )) + mhp_default_online_type =MMOP_ONLINE_KERNEL ; +else if (IS_ENABLED (CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_MOVABLE )) + mhp_default_online_type =MMOP_ONLINE_MOVABLE ; +else + mhp_default_online_type =MMOP_OFFLINE ; + +return mhp_default_online_type; +} + +void mhp_set_default_online_type (int online_type) +{ + mhp_default_online_type = online_type; +}static int __init setup_memhp_default_state (char *str) {
@@ -1321,7 +1340,7 @@ static int check_hotplug_memory_range(u64 start, u64 size)static int online_memory_block (struct memory_block *mem,void *arg) { - mem->online_type = mhp_default_online_type; + mem->online_type =mhp_get_default_online_type ();return device_online (&mem->dev); }
@@ -1570,7 +1589,7 @@ int add_memory_resource(int nid, struct resource *res, mhp_t mhp_flags)merge_system_ram_resource (res);/* online pages if requested */ -if (mhp_default_online_type !=MMOP_OFFLINE ) +if (mhp_get_default_online_type () !=MMOP_OFFLINE )walk_memory_blocks (start, size,NULL , online_memory_block);return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 382/1376 mm: convert memory block states (MEM_*) macros to enum
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Israel Batista <[email protected]>
[ Upstream commit 1a4f70f6851a1916c4f0e52731c7ecfe99bf36e6 ]
Patch series "mm: Convert memory block states (MEM_*) macros to enums", v2.
The MEM_* constants indicating the state of a memory block are currently defined as macros, meaning their definitions will be omitted from the debuginfo on most kernel builds. This makes it harder for debuggers to correctly map the block state at runtime, which can be quite useful when analysing errors related to memory hot plugging and unplugging with tools such as drgn.
Converting the constants to an enum ensures the correct information is emitted by the compiler and available for the debugger, without needing to hard-code them into the debugger and track their changes.
This patch series aims to replace the current macros with a newly created enum named memory_block_state, while also taking advantage of the compile time guarantees that we get when using enums.
The first patch does the conversion of the macros to an enum, while the 2nd and 3rd patches use this enum to clean up some type declarations and make sure that only valid values are used.
This patch (of 3):
Converting the MEM_* constants from macros to an enum ensures that their values will be correctly emitted in the debug symbols, making it easier to trace the meaning of each value when debugging with tools such as drgn, without the need to hard-code the values.
Since the values are mutually exclusive and they are not exposed directly to userspace, I also dropped the misleading pattern (1<<X) that made it look like they were combinable flags.
Stable-dep-of: 2ebce860bdd7 ("mm/mm_init: handle alloc_percpu failure in free_area_init_core_hotplug")
--- include/linux/memory.h | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-)
include/linux/memory.h +12 -10
@@ -64,6 +64,18 @@ struct memory_group { }; }; +enum memory_block_state { +/* These states are exposed to userspace as text strings in sysfs */ +MEM_ONLINE ,/* exposed to userspace */ +MEM_GOING_OFFLINE ,/* exposed to userspace */ +MEM_OFFLINE ,/* exposed to userspace */ +MEM_GOING_ONLINE , +MEM_CANCEL_ONLINE , +MEM_CANCEL_OFFLINE , +MEM_PREPARE_ONLINE , +MEM_FINISH_OFFLINE , +}; +struct memory_block {unsigned long start_section_nr;unsigned long state;/* serialized by the dev->lock */
@@ -89,16 +101,6 @@ int arch_get_memory_phys_device(unsigned long start_pfn);unsigned long memory_block_size_bytes (void );int set_memory_block_size_order (unsigned int order); -/* These states are exposed to userspace as text strings in sysfs */ -#define MEM_ONLINE (1<<0)/* exposed to userspace */ -#define MEM_GOING_OFFLINE (1<<1)/* exposed to userspace */ -#define MEM_OFFLINE (1<<2)/* exposed to userspace */ -#define MEM_GOING_ONLINE (1<<3) -#define MEM_CANCEL_ONLINE (1<<4) -#define MEM_CANCEL_OFFLINE (1<<5) -#define MEM_PREPARE_ONLINE (1<<6) -#define MEM_FINISH_OFFLINE (1<<7) -struct memory_notify {/* * The altmap_start_pfn and altmap_nr_pages fields are designated for
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 383/1376 mm: change type of state in struct memory_block
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Israel Batista <[email protected]>
[ Upstream commit 8bc7ba3d265d6ee698de4b1941b7e8f7d91a0562 ]
The state of a memory block should be restricted to values specified in the documentation of the memory hotplug API. However, since the state field in the memory_block struct was defined as an unsigned long, this restriction was not enforced at compile time.
With the introduction of the enum memory_block_state, it is now possible to incorporate the desired semantics in the field declaration and enforce these restrictions at compile time.
Stable-dep-of: 2ebce860bdd7 ("mm/mm_init: handle alloc_percpu failure in free_area_init_core_hotplug")
--- drivers/base/memory.c | 2 +- include/linux/memory.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
drivers/base/memory.c +1 -1
@@ -160,7 +160,7 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr,break ;default :WARN_ON (1 ); -return sysfs_emit (buf,"ERROR-UNKNOWN-%ld\n" , mem->state); +return sysfs_emit (buf,"ERROR-UNKNOWN-%d\n" , mem->state); }return sysfs_emit (buf,"%s\n" , output);
include/linux/memory.h +1 -1
@@ -78,7 +78,7 @@ enum memory_block_state {struct memory_block {unsigned long start_section_nr; -unsigned long state;/* serialized by the dev->lock */ +enum memory_block_state state;/* serialized by the dev->lock */ int online_type;/* for passing data to online routine */ int nid;/* NID for this memory block */ /*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 384/1376 mm: name the anonymous MMOP enum as enum mmop
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gregory Price <[email protected]>
[ Upstream commit c5c48345135ff04e039377020df23294d59aa59a ]
Give the MMOP enum (MMOP_OFFLINE, MMOP_ONLINE, etc) a proper type name so the compiler can help catch invalid values being assigned to variables of this type.
Leave the existing functions returning int alone to allow for value-or-error pattern to remain unchanged without churn.
mmop_default_online_type is left as int because it uses the -1 sentinal value to signal it hasn't been initialized yet.
Keep the uint8_t buffer in offline_and_remove_memory() as-is for space efficiency, with an explicit cast when we consume the value.
Move the enum definition before the CONFIG_MEMORY_HOTPLUG guard so it is unconditionally available for struct memory_block in memory.h.
No functional change.
Stable-dep-of: 2ebce860bdd7 ("mm/mm_init: handle alloc_percpu failure in free_area_init_core_hotplug")
--- drivers/base/memory.c | 2 +- include/linux/memory.h | 3 ++- include/linux/memory_hotplug.h | 16 ++++++++-------- mm/memory_hotplug.c | 10 +++++----- 4 files changed, 16 insertions(+), 15 deletions(-)
drivers/base/memory.c +1 -1
@@ -435,7 +435,7 @@ static ssize_t phys_device_show(struct device *dev,static int print_allowed_zone (char *buf,int len,int nid,struct memory_group *group,unsigned long start_pfn,unsigned long nr_pages, -int online_type,struct zone *default_zone) +enum mmop online_type,struct zone *default_zone) {struct zone *zone;
include/linux/memory.h +2 -1
@@ -19,6 +19,7 @@#include <linux/node.h> #include <linux/compiler.h> #include <linux/mutex.h> +#include <linux/memory_hotplug.h> #define MIN_MEMORY_BLOCK_SIZE (1UL << SECTION_SIZE_BITS)
@@ -79,7 +80,7 @@ enum memory_block_state {struct memory_block {unsigned long start_section_nr;enum memory_block_state state;/* serialized by the dev->lock */ -int online_type;/* for passing data to online routine */ +enum mmop online_type;/* for passing data to online routine */ int nid;/* NID for this memory block */ /* * The single zone of this memory block if all PFNs of this memory block
include/linux/memory_hotplug.h +8 -8
@@ -16,11 +16,8 @@ struct resource;struct vmem_altmap ;struct dev_pagemap ; -#ifdef CONFIG_MEMORY_HOTPLUG -struct page *pfn_to_online_page (unsigned long pfn); -/* Types for control the zone type of onlined and offlined memory */ -enum { +enum mmop {/* Offline the memory. */ MMOP_OFFLINE =0 ,/* Online the memory. Zone depends, see default_zone_for_pfn(). */
@@ -31,6 +28,9 @@ enum { MMOP_ONLINE_MOVABLE, }; +#ifdef CONFIG_MEMORY_HOTPLUG +struct page *pfn_to_online_page (unsigned long pfn); +/* Flags for add_memory() and friends to specify memory hotplug details. */ typedef int __bitwise mhp_t ;
@@ -303,8 +303,8 @@ static inline void __remove_memory(u64 start, u64 size) {}#ifdef CONFIG_MEMORY_HOTPLUG /* Default online_type (MMOP_*) when new memory blocks are added. */ -extern int mhp_get_default_online_type (void ); -extern void mhp_set_default_online_type (int online_type); +extern enum mmop mhp_get_default_online_type (void ); +extern void mhp_set_default_online_type (enum mmop online_type);extern void __ref free_area_init_core_hotplug (struct pglist_data *pgdat);extern int __add_memory (int nid,u64 start,u64 size,mhp_t mhp_flags);extern int add_memory (int nid,u64 start,u64 size,mhp_t mhp_flags);
@@ -327,8 +327,8 @@ extern void sparse_remove_section(unsigned long pfn, unsigned long nr_pages, struct dev_pagemap *pgmap);extern struct page *sparse_decode_mem_map (unsigned long coded_mem_map,unsigned long pnum); -extern struct zone *zone_for_pfn_range (int online_type,int nid, -struct memory_group *group,unsigned long start_pfn, +extern struct zone *zone_for_pfn_range (enum mmop online_type, +int nid,struct memory_group *group,unsigned long start_pfn,unsigned long nr_pages);extern int arch_create_linear_mapping (int nid,u64 start,u64 size,struct mhp_params *params);
mm/memory_hotplug.c +5 -5
@@ -220,7 +220,7 @@ void put_online_mems(void)bool movable_node_enabled = false;static int mhp_default_online_type =-1 ; -int mhp_get_default_online_type (void ) +enum mmop mhp_get_default_online_type (void ) {if (mhp_default_online_type >=0 )return mhp_default_online_type;
@@ -239,7 +239,7 @@ int mhp_get_default_online_type(void)return mhp_default_online_type; } -void mhp_set_default_online_type (int online_type) +void mhp_set_default_online_type (enum mmop online_type) { mhp_default_online_type = online_type; }
@@ -1060,7 +1060,7 @@ static inline struct zone *default_zone_for_pfn(int nid, unsigned long start_pfnreturn movable_node_enabled ? movable_zone : kernel_zone; } -struct zone *zone_for_pfn_range (int online_type,int nid, +struct zone *zone_for_pfn_range (enum mmop online_type,int nid,struct memory_group *group,unsigned long start_pfn,unsigned long nr_pages) {
@@ -2349,7 +2349,7 @@ EXPORT_SYMBOL_GPL(remove_memory);static int try_offline_memory_block (struct memory_block *mem,void *arg) { -uint8_t online_type =MMOP_ONLINE_KERNEL ; +enum mmop online_type =MMOP_ONLINE_KERNEL ;uint8_t **online_types = arg;struct page *page;int rc;
@@ -2382,7 +2382,7 @@ static int try_reonline_memory_block(struct memory_block *mem, void *arg)int rc;if (**online_types !=MMOP_OFFLINE ) { - mem->online_type = **online_types; + mem->online_type = (enum mmop )**online_types; rc =device_online (&mem->dev);if (rc <0 ) pr_warn("%s: Failed to re-online memory: %d",
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 385/1376 mm/mm_init: handle alloc_percpu failure in free_area_init_core_hotplug
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gregory Price <[email protected]>
[ Upstream commit 2ebce860bdd7ae5e13002811bc9bbbf33fcfc221 ]
We miss a failed allocation check for pgdat->per_cpu_nodestats, which results in a NULL deref when we offset into the per-cpu area.
Propagate -ENOMEM up the stack and leave per_cpu_nodestats pointing at boot_nodestats so a later online can retry the allocation.
hotadd_init_pgdat() returns NULL on failure, which __try_online_node() already maps to -ENOMEM.
On failure nothing needs to be unwound:
- the node is never marked online
- per_cpu_nodestats is left pointing at boot_nodestats
- __add_memory_resource() cleans up pending memblock resources
- later online attempts retry the per_cpu_nodestats allocation
--- include/linux/memory_hotplug.h | 2 +- mm/memory_hotplug.c | 3 ++- mm/mm_init.c | 14 +++++++++++--- 3 files changed, 14 insertions(+), 5 deletions(-)
include/linux/memory_hotplug.h +1 -1
@@ -305,7 +305,7 @@ static inline void __remove_memory(u64 start, u64 size) {}/* Default online_type (MMOP_*) when new memory blocks are added. */ extern enum mmop mhp_get_default_online_type (void );extern void mhp_set_default_online_type (enum mmop online_type); -extern void __ref free_area_init_core_hotplug (struct pglist_data *pgdat); +int __ref free_area_init_core_hotplug (struct pglist_data *pgdat);extern int __add_memory (int nid,u64 start,u64 size,mhp_t mhp_flags);extern int add_memory (int nid,u64 start,u64 size,mhp_t mhp_flags); extern int add_memory_resource(int nid, struct resource *resource,
mm/memory_hotplug.c +2 -1
@@ -1266,7 +1266,8 @@ static pg_data_t *hotadd_init_pgdat(int nid) pgdat =NODE_DATA (nid);/* init node's zones as empty zones, we don't have any present pages.*/ -free_area_init_core_hotplug (pgdat); +if (free_area_init_core_hotplug (pgdat)) +return NULL ;/* * The node we allocated has no zone fallback lists. For avoiding
mm/mm_init.c +11 -3
@@ -1519,7 +1519,7 @@ void __init set_pageblock_order(void)* NOTE: this function is only called during memory hotplug */ #ifdef CONFIG_MEMORY_HOTPLUG -void __ref free_area_init_core_hotplug (struct pglist_data *pgdat) +int __ref free_area_init_core_hotplug (struct pglist_data *pgdat) {int nid = pgdat->node_id;enum zone_type z;
@@ -1527,8 +1527,14 @@ void __ref free_area_init_core_hotplug(struct pglist_data *pgdat)pgdat_init_internals (pgdat); -if (pgdat->per_cpu_nodestats == &boot_nodestats) - pgdat->per_cpu_nodestats = alloc_percpu(struct per_cpu_nodestat); +if (pgdat->per_cpu_nodestats == &boot_nodestats) { +struct per_cpu_nodestat __percpu *p; + + p = alloc_percpu(struct per_cpu_nodestat); +if (!p) +return -ENOMEM ; + pgdat->per_cpu_nodestats = p; + }/* * Reset the nr_zones, order and highest_zoneidx before reuse.
@@ -1566,6 +1572,8 @@ void __ref free_area_init_core_hotplug(struct pglist_data *pgdat) zone->present_pages =0 ; zone_init_internals(zone, z, nid, 0); } + +return 0 ; }#endif
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 386/1376 dmaengine: mediatek: mtk-uart-apdma: Return -ENOMEM on memory allocation failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vladimir Zapolskiy <[email protected]>
[ Upstream commit 467265c750edd7ab43803deeafe7d3120a791d32 ]
If dynamic memory allocation in driver's probe function execution fails, it should be reported to the driver's framework with -ENOMEM error code.
--- drivers/dma/mediatek/mtk-uart-apdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/dma/mediatek/mtk-uart-apdma.c +1 -1
@@ -530,7 +530,7 @@ static int mtk_uart_apdma_probe(struct platform_device *pdev)for (i =0 ; i < mtkd->dma_requests; i++) { c =devm_kzalloc (mtkd->ddev.dev,sizeof (*c),GFP_KERNEL );if (!c) { - rc = -ENODEV ; + rc = -ENOMEM ; goto err_no_dma; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 387/1376 dmaengine: xilinx_dma: Fix channel idle state management in AXIDMA and MCDMA interrupt handlers
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Suraj Gupta <[email protected]>
[ Upstream commit 0b6d055edb55ecadadf54e930c2b4fab76fa9a5a ]
Fix a race condition in AXIDMA and MCDMA irq handlers where the channel could be incorrectly marked as idle and attempt spurious transfers when descriptors are still being processed.
The issue occurs when:
1. Multiple descriptors are queued and active.
2. An interrupt fires after completing some descriptors.
3. xilinx_dma_complete_descriptor() moves completed descriptors to done_list.
4. Channel is marked idle and start_transfer() is called even though active_list still contains unprocessed descriptors.
5. This leads to premature transfer attempts and potential descriptor corruption or missed completions.
Only mark the channel as idle and start new transfers when the active list is actually empty, ensuring proper channel state management and avoiding spurious transfer attempts.
--- drivers/dma/xilinx/xilinx_dma.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
drivers/dma/xilinx/xilinx_dma.c +8 -4
@@ -1869,8 +1869,10 @@ static irqreturn_t xilinx_mcdma_irq_handler(int irq, void *data)if (status &XILINX_MCDMA_IRQ_IOC_MASK ) {spin_lock (&chan->lock);xilinx_dma_complete_descriptor (chan); - chan->idle = true; - chan->start_transfer (chan); +if (list_empty (&chan->active_list)) { + chan->idle = true; + chan->start_transfer (chan); + }spin_unlock (&chan->lock); }
@@ -1926,8 +1928,10 @@ static irqreturn_t xilinx_dma_irq_handler(int irq, void *data) XILINX_DMA_DMASR_DLY_CNT_IRQ)) {spin_lock (&chan->lock);xilinx_dma_complete_descriptor (chan); - chan->idle = true; - chan->start_transfer (chan); +if (list_empty (&chan->active_list)) { + chan->idle = true; + chan->start_transfer (chan); + }spin_unlock (&chan->lock); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 388/1376 dmaengine: hisilicon: Return -ENOMEM on dynamic memory allocation in probe
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vladimir Zapolskiy <[email protected]>
[ Upstream commit cbabdd6ce1b313b5877c7fbb2f5e2f7936564d2f ]
Out of memory situation on driver's probe is expected to be reported to the driver's framework with a proper -ENOMEM error code.
--- drivers/dma/hisi_dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/dma/hisi_dma.c +1 -1
@@ -983,7 +983,7 @@ static int hisi_dma_probe(struct pci_dev *pdev, const struct pci_device_id *id) hdma_dev =devm_kzalloc (dev,struct_size (hdma_dev, chan, chan_num),GFP_KERNEL );if (!hdma_dev) -return -EINVAL ; +return -ENOMEM ; hdma_dev->base =pcim_iomap_table (pdev)[PCI_BAR_2 ]; hdma_dev->pdev = pdev;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 389/1376 soundwire: qcom: Fix port exhaustion check in stream_alloc_ports
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Srinivas Kandagatla <[email protected]>
[ Upstream commit 6ccec91c3535b07310e12d32fe9c67ff8d31d965 ]
find_first_zero_bit(mask, n) returns n (not n+1) when all bits are set, so the guard pn > maxport is never true on exhaustion. The driver would silently call set_bit(maxport, port_mask) and assign the out-of-range port instead of returning -EBUSY. Fix the comparison to pn >= maxport.
--- drivers/soundwire/qcom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/soundwire/qcom.c +1 -1
@@ -1204,7 +1204,7 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl,else pn =find_first_zero_bit (port_mask, maxport); -if (pn > maxport) { +if (pn >= maxport) {dev_err (ctrl->dev,"All ports busy\n" ); ret = -EBUSY ; goto out;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 390/1376 iio: orientation: hid-sensor-rotation: Avoid race between callback setup and device exposure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sanjay Chitroda <[email protected]>
[ Upstream commit 0e32649a7cf3cd784862f8dc0c68a5134731bfff ]
The driver currently exposes the IIO device to userspace before completing sensor hub callback registration, and similarly removes callbacks while the device can still be accessed during teardown.
This creates a timing window where userspace may enable the buffer before callbacks are available. In such cases:
- samples can be dropped,
- buffered reads may observe stale or no data.
Reorder probe and remove paths to ensure callbacks are active before device exposure and are removed after device is no longer accessible.
This avoids a race window leading to data loss.
--- drivers/iio/orientation/hid-sensor-rotation.c | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-)
drivers/iio/orientation/hid-sensor-rotation.c +10 -10
@@ -337,12 +337,6 @@ static int hid_dev_rot_probe(struct platform_device *pdev)return ret; } - ret =iio_device_register (indio_dev); -if (ret) { -dev_err (&pdev->dev,"device register failed\n" ); - goto error_remove_trigger; - } - rot_state->callbacks.send_event = dev_rot_proc_event; rot_state->callbacks.capture_sample = dev_rot_capture_sample; rot_state->callbacks.pdev = pdev;
@@ -350,13 +344,19 @@ static int hid_dev_rot_probe(struct platform_device *pdev) &rot_state->callbacks);if (ret) {dev_err (&pdev->dev,"callback reg failed\n" ); - goto error_iio_unreg; + goto error_remove_trigger; + } + + ret =iio_device_register (indio_dev); +if (ret) { +dev_err (&pdev->dev,"device register failed\n" ); + goto error_remove_callback; }return 0 ; -error_iio_unreg: -iio_device_unregister (indio_dev); +error_remove_callback: +sensor_hub_remove_callback (hsdev, hsdev->usage); error_remove_trigger:hid_sensor_remove_trigger (indio_dev, &rot_state->common_attributes);return ret;
@@ -369,8 +369,8 @@ static void hid_dev_rot_remove(struct platform_device *pdev)struct iio_dev *indio_dev =platform_get_drvdata (pdev);struct dev_rot_state *rot_state =iio_priv (indio_dev); -sensor_hub_remove_callback (hsdev, hsdev->usage);iio_device_unregister (indio_dev); +sensor_hub_remove_callback (hsdev, hsdev->usage);hid_sensor_remove_trigger (indio_dev, &rot_state->common_attributes); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 391/1376 csky: Fix a4/a5 restoration in syscall trace path
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hanlin Song <[email protected]>
[ Upstream commit abb81e5ce7d995baa41556b8125fa59e28ba3be8 ]
The syscall trace path reloads syscall arguments from pt_regs before calling the syscall handler. On C-SKY ABIv2, the 5th and 6th syscall arguments are prepared as stack arguments before invoking syscallid.
The current code adjusts sp before loading LSAVE_A4 and LSAVE_A5. Since those offsets are relative to the original pt_regs base, loading them after changing sp fetches the wrong slots. As a result, traced syscalls that use the 5th or 6th argument may receive corrupted arguments.
This is visible with mmap2(), which takes six arguments. A small PTRACE_SYSCALL reproducer opens a file and maps one page with:
mmap(NULL, 4096, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0)
Before the fix, the traced child fails the mmap and exits with 12. After the fix, the mapping succeeds and the child exits with 0.
Fix the trace path by loading a4/a5 from pt_regs before changing sp.
Tested on: ck860f, linux-4.19.15, C-SKY abiv2
--- arch/csky/kernel/entry.S | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
arch/csky/kernel/entry.S +3 -3
@@ -93,11 +93,11 @@ csky_syscall_trace: ldw a2, (sp, LSAVE_A2) ldw a3, (sp, LSAVE_A3) #if defined(__CSKYABIV2__) - subi sp, 8 ldw r9, (sp, LSAVE_A4) + ldw r10, (sp, LSAVE_A5) + subi sp, 8 stw r9, (sp, 0x0) - ldw r9, (sp, LSAVE_A5) - stw r9, (sp, 0x4) + stw r10, (sp, 0x4) jsr syscallid /* Do system call */ addi sp, 8 #else
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 392/1376 selftests/rseq: Replace glibc-specific __GNUC_PREREQ with portable check
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hisam Mehboob <[email protected]>
[ Upstream commit d7b2769f8dba3e5f40d2a8a11988812d51160b17 ]
Building the rseq selftests against musl libc fails because musl's <features.h> does not provide the glibc-specific __GNUC_PREREQ macro:
error: missing binary operator before token '('
Replace __GNUC_PREREQ(11, 1) with an equivalent check using __GNUC__ and __GNUC_MINOR__ directly. This pattern is portable across all C library implementations and is already used elsewhere in the tools/ tree (e.g., tools/include/linux/string.h).
This also allows removing the #include <features.h>, which was only needed for __GNUC_PREREQ.
--- tools/testing/selftests/rseq/rseq-x86-thread-pointer.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
tools/testing/selftests/rseq/rseq-x86-thread-pointer.h +1 -3
@@ -8,13 +8,11 @@ #ifndef _RSEQ_X86_THREAD_POINTER #define _RSEQ_X86_THREAD_POINTER -#include <features.h> - #ifdef __cplusplus extern "C" { #endif -#if __GNUC_PREREQ (11, 1) +#if __GNUC__ > 11 || (__GNUC__ == 11 && __GNUC_MINOR__ >= 1) static inline void *rseq_thread_pointer(void) { return __builtin_thread_pointer();
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 393/1376 platform/chrome: sensorhub: Fix memory overread in ring handler
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tzung-Bi Shih <[email protected]>
[ Upstream commit d1ceb2b2324717fa30b44d56ef0c52813e239569 ]
max_response and sensor_num are read from different EC commands:
- max_response is from cros_ec_get_proto_info().
ec_dev->max_response = info->max_response_packet_size -
sizeof(struct ec_host_response);- sensor_num is from cros_ec_get_sensor_count().
sensor_num = cros_ec_get_sensor_count(ec);
With a malfunctioning EC firmware, it is possible that the msg->insize (i.e., fifo_info_length in the context) could be clamped in cros_ec_cmd_xfer() because msg->insize is greater than max_response.
int fifo_info_length =
sizeof(struct ec_response_motion_sense_fifo_info) + sizeof(u16) * sensorhub->sensor_num;
This means the number of read bytes could be less than expected. As a result, the subsequent memcpy() in cros_ec_sensorhub_ring_handler() overreads the resp->fifo_info buffer.
Check the return value of cros_ec_cmd_xfer_status() and abort if the number of bytes read does not match the expected length.
--- drivers/platform/chrome/cros_ec_sensorhub_ring.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/platform/chrome/cros_ec_sensorhub_ring.c +8 -1
@@ -825,8 +825,15 @@ static void cros_ec_sensorhub_ring_handler(struct cros_ec_sensorhub *sensorhub) sensorhub->msg->outsize =1 ; sensorhub->msg->insize = fifo_info_length; -if (cros_ec_cmd_xfer_status (ec->ec_dev, sensorhub->msg) <0 ) + ret =cros_ec_cmd_xfer_status (ec->ec_dev, sensorhub->msg); +if (ret <0 ) + goto error; +if (ret != fifo_info_length) { +dev_warn_ratelimited (sensorhub->dev, +"Mismatch read length: size %d - expected %d\n" , + ret, fifo_info_length); goto error; + }memcpy (fifo_info, &sensorhub->resp->fifo_info, fifo_info_length);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 394/1376 wifi: rtw89: fix HE extended capability length check
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit 2aba608a86e9b099c9af2ea70b620552dee2b628 ]
rtw89_mac_check_he_obss_narrow_bw_ru_iter() reads extended capability byte 10, but rejects only datalen values below 10. Byte 10 requires at least 11 bytes.
Require datalen >= 11 before reading data[10].
--- drivers/net/wireless/realtek/rtw89/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/realtek/rtw89/mac.c +1 -1
@@ -4730,7 +4730,7 @@ static void rtw89_mac_check_he_obss_narrow_bw_ru_iter(struct wiphy *wiphy, elem =cfg80211_find_elem (WLAN_EID_EXT_CAPABILITY , ies->data, ies->len); -if (!elem || elem->datalen <10 || +if (!elem || elem->datalen <11 || !(elem->data[10 ] &WLAN_EXT_CAPA10_OBSS_NARROW_BW_RU_TOLERANCE_SUPPORT )) *tolerated = false;rcu_read_unlock ();
Signature · 1 line
2.53.0