From aa74098f29b3027111baf17c21d6e30a3656e2d0 Mon Sep 17 00:00:00 2001 From: Alex Waterman Date: Thu, 21 Jan 2016 14:44:43 -0800 Subject: gpu: nvgpu: Fix gk20a_sync_pt_has_signaled() Fix a reentrancy problem in gk20a_sync_pt_has_signaled() where one thread could clear a pointer before another thread tried to access it. A spinlock was added to the gk20a_sync_pt struct which is used to ensure that the underyling gk20a_sync_pt data is accessed in a sane manner. Bug 1604892 Change-Id: I270d89def7b986405a3167285d51ceda950c7b82 Signed-off-by: Alex Waterman Reviewed-on: http://git-master/r/935909 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Terje Bergstrom GVS: Gerrit_Virtual_Submit --- drivers/gpu/nvgpu/gk20a/sync_gk20a.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/nvgpu/gk20a/sync_gk20a.c b/drivers/gpu/nvgpu/gk20a/sync_gk20a.c index 74cf5c5a..8740f0e2 100644 --- a/drivers/gpu/nvgpu/gk20a/sync_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/sync_gk20a.c @@ -1,7 +1,7 @@ /* * GK20A Sync Framework Integration * - * Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "../../../staging/android/sync.h" #include "semaphore_gk20a.h" @@ -44,6 +45,12 @@ struct gk20a_sync_pt { struct gk20a_sync_timeline *obj; struct sync_fence *dep; ktime_t dep_timestamp; + + /* + * A spinlock is necessary since there are times when this lock + * will be acquired in interrupt context. + */ + spinlock_t lock; }; struct gk20a_sync_pt_inst { @@ -149,7 +156,10 @@ static struct gk20a_sync_pt *gk20a_sync_pt_create_shared( } } + spin_lock_init(&shared->lock); + gk20a_semaphore_get(sema); + return shared; } @@ -194,14 +204,20 @@ static struct sync_pt *gk20a_sync_pt_dup_inst(struct sync_pt *sync_pt) return &pti->pt; } +/* + * This function must be able to run on the same sync_pt concurrently. This + * requires a lock to protect access to the sync_pt's internal data structures + * which are modified as a side effect of calling this function. + */ static int gk20a_sync_pt_has_signaled(struct sync_pt *sync_pt) { struct gk20a_sync_pt *pt = to_gk20a_sync_pt(sync_pt); struct gk20a_sync_timeline *obj = pt->obj; - bool signaled; + bool signaled = true; + spin_lock(&pt->lock); if (!pt->sema) - return true; + goto done; /* Acquired == not realeased yet == active == not signaled. */ signaled = !gk20a_semaphore_is_acquired(pt->sema); @@ -232,6 +248,9 @@ static int gk20a_sync_pt_has_signaled(struct sync_pt *sync_pt) gk20a_semaphore_put(pt->sema); pt->sema = NULL; } +done: + spin_unlock(&pt->lock); + return signaled; } -- cgit v1.2.2