drm/amd/pm: fix torn gpu metrics reads

amdgpu_dpm_get_gpu_metrics() returns a pointer to the shared metrics cache
after dropping adev->pm.mutex. The sysfs path then copies from that pointer.
Another reader can refresh the cache in place during the copy and return a
snapshot containing data from two generations.

Pass caller-provided storage through the DPM interface and copy the metrics
while the mutex is held. This keeps the cache pointer private and makes each
sysfs read observe one complete sample.

Fixes: 25c933b1c4 ("drm/amd/powerplay: add new sysfs interface for retrieving gpu metrics(V2)")
Signed-off-by: Yang Wang <kevinyang.wang@amd.com>
Reviewed-by: Kenneth Feng <kenneth.feng@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit 862333bb48)
Cc: stable@vger.kernel.org
This commit is contained in:
Yang Wang
2026-07-28 20:00:06 -04:00
committed by Alex Deucher
parent bb493058c3
commit 048f4541b7
3 changed files with 12 additions and 11 deletions
+9 -3
View File
@@ -1434,17 +1434,23 @@ int amdgpu_dpm_set_power_profile_mode(struct amdgpu_device *adev,
return ret;
}
int amdgpu_dpm_get_gpu_metrics(struct amdgpu_device *adev, void **table)
ssize_t amdgpu_dpm_get_gpu_metrics(struct amdgpu_device *adev, void *buf,
size_t size)
{
const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
int ret = 0;
void *table;
ssize_t ret;
if (!pp_funcs->get_gpu_metrics)
return 0;
mutex_lock(&adev->pm.mutex);
ret = pp_funcs->get_gpu_metrics(adev->powerplay.pp_handle,
table);
&table);
if (ret > 0) {
ret = min_t(ssize_t, ret, size);
memcpy(buf, table, ret);
}
mutex_unlock(&adev->pm.mutex);
return ret;
+1 -7
View File
@@ -1774,7 +1774,6 @@ static ssize_t amdgpu_get_gpu_metrics(struct device *dev,
{
struct drm_device *ddev = dev_get_drvdata(dev);
struct amdgpu_device *adev = drm_to_adev(ddev);
void *gpu_metrics;
ssize_t size = 0;
int ret;
@@ -1782,15 +1781,10 @@ static ssize_t amdgpu_get_gpu_metrics(struct device *dev,
if (ret)
return ret;
size = amdgpu_dpm_get_gpu_metrics(adev, &gpu_metrics);
size = amdgpu_dpm_get_gpu_metrics(adev, buf, PAGE_SIZE - 1);
if (size <= 0)
goto out;
if (size >= PAGE_SIZE)
size = PAGE_SIZE - 1;
memcpy(buf, gpu_metrics, size);
out:
amdgpu_pm_put_access(adev);
+2 -1
View File
@@ -518,7 +518,8 @@ int amdgpu_dpm_get_power_profile_mode(struct amdgpu_device *adev,
char *buf);
int amdgpu_dpm_set_power_profile_mode(struct amdgpu_device *adev,
long *input, uint32_t size);
int amdgpu_dpm_get_gpu_metrics(struct amdgpu_device *adev, void **table);
ssize_t amdgpu_dpm_get_gpu_metrics(struct amdgpu_device *adev, void *buf,
size_t size);
ssize_t amdgpu_dpm_get_xcp_metrics(struct amdgpu_device *adev, int xcp_id,
void *table);
ssize_t amdgpu_dpm_get_temp_metrics(struct amdgpu_device *adev,