aca_handle_is_valid() returned false if !list_empty(&handle->node)
evaluated to true. Because active registered handles have non-empty
nodes in the handle list, valid handles evaluated as invalid.
Consequently, amdgpu_aca_get_error_data() returned -EOPNOTSUPP
whenever aca_handle_is_valid() evaluated to true.

Fix the logic in aca_handle_is_valid() to verify that the handle is
non-NULL, contains a valid mask, and is currently registered in the
list. Update amdgpu_aca_get_error_data() to check for invalid
handles and return 0 instead of -EOPNOTSUPP so non-ACA blocks in
global RAS queries pass through safely without breaking error
telemetry.

Additionally, modify remove_aca_handle() to unlink handle->node
under mgr->lock using list_del_init() prior to calling
aca_fini_error_cache(). Standard list_del() leaves node pointers
poisoned, causing !list_empty() in aca_handle_is_valid() to evaluate
to true for removed handles. Unlinking under lock first prevents
concurrent list traversals from racing on node pointers and stops
background queries from referencing destroyed error cache mutexes during
handle teardown.

Signed-off-by: Sreeraj S Kurup <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c
index c76664af9902..c35f6be2ef77 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c
@@ -586,10 +586,7 @@ static int __aca_get_error_data(struct amdgpu_device 
*adev, struct aca_handle *h
 
 static bool aca_handle_is_valid(struct aca_handle *handle)
 {
-       if (!handle->mask || !list_empty(&handle->node))
-               return false;
-
-       return true;
+       return handle && handle->mask && !list_empty(&handle->node);
 }
 
 int amdgpu_aca_get_error_data(struct amdgpu_device *adev, struct aca_handle 
*handle,
@@ -599,8 +596,8 @@ int amdgpu_aca_get_error_data(struct amdgpu_device *adev, 
struct aca_handle *han
        if (!handle || !err_data)
                return -EINVAL;
 
-       if (aca_handle_is_valid(handle))
-               return -EOPNOTSUPP;
+       if (!aca_handle_is_valid(handle))
+               return 0;
 
        if ((type < 0) || (!(BIT(type) & handle->mask)))
                return  0;
@@ -716,9 +713,13 @@ static void remove_aca_handle(struct aca_handle *handle)
 {
        struct aca_handle_manager *mgr = handle->mgr;
 
-       aca_fini_error_cache(handle);
-       list_del(&handle->node);
+       mutex_lock(&mgr->lock);
+       list_del_init(&handle->node);
        mgr->nr_handles--;
+       mutex_unlock(&mgr->lock);
+       aca_fini_error_cache(handle);
+       kfree(handle);
+
 }
 
 static void remove_aca_sysfs(struct aca_handle *handle)
-- 
2.54.0

Reply via email to