staging: vc04_services: use kref + RCU to reference count services
authorMarcelo Diop-Gonzalez <marcgonzalez@google.com>
Wed, 12 Feb 2020 18:43:32 +0000 (13:43 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 12 Feb 2020 21:40:43 +0000 (13:40 -0800)
commit3c27a36f2711880de5e6629fbba71bfdbbf47ceb
tree883b41127d16f136c4e392e7f7d28e5848e45fb5
parent0e35fa615e0baf5d95dafc4362b349b8406676ab
staging: vc04_services: use kref + RCU to reference count services

Currently reference counts are implemented by locking service_spinlock
and then incrementing the service's ->ref_count field, calling
kfree() when the last reference has been dropped. But at the same
time, there's code in multiple places that dereferences pointers
to services without having a reference, so there could be a race there.

It should be possible to avoid taking any lock in unlock_service()
or service_release() because we are setting a single array element
to NULL, and on service creation, a mutex is locked before looking
for a NULL spot to put the new service in.

Using a struct kref and RCU-delaying the freeing of services fixes
this race condition while still making it possible to skip
grabbing a reference in many places. Also it avoids the need to
acquire a single spinlock when e.g. taking a reference on
state->services[i] when somebody else is in the middle of taking
a reference on state->services[j].

Signed-off-by: Marcelo Diop-Gonzalez <marcgonzalez@google.com>
Link: https://lore.kernel.org/r/3bf6f1ec6ace64d7072025505e165b8dd18b25ca.1581532523.git.marcgonzalez@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h