summaryrefslogtreecommitdiffstats
path: root/drivers/staging/greybus/operation.c
diff options
context:
space:
mode:
authorJohan Hovold <johan@hovoldconsulting.com>2015-07-09 15:17:58 +0200
committerGreg Kroah-Hartman <gregkh@google.com>2015-07-13 15:29:27 -0700
commit85109f7ddde4b1842bfb08741a8b461e31ef2c4f (patch)
tree4bd94039cb5d36bd53f8299b5fb4634474d734d7 /drivers/staging/greybus/operation.c
parent5c1ac6945526c76258869c8c04632ab5ae61bdab (diff)
greybus: operation: fix operation-destroy race
Make sure to acquire the connection-list lock atomically when releasing the final reference. This allows the list to be traversed and references to be acquired (while holding the lock) without racing with the destructor. Suggested-by: Greg Kroah-Hartman <gregkh@google.com> Signed-off-by: Johan Hovold <johan@hovoldconsulting.com> Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Diffstat (limited to 'drivers/staging/greybus/operation.c')
-rw-r--r--drivers/staging/greybus/operation.c11
1 files changed, 6 insertions, 5 deletions
diff --git a/drivers/staging/greybus/operation.c b/drivers/staging/greybus/operation.c
index 9e2ff7dd278a..f8d7df9ad3c4 100644
--- a/drivers/staging/greybus/operation.c
+++ b/drivers/staging/greybus/operation.c
@@ -528,14 +528,12 @@ EXPORT_SYMBOL_GPL(gb_operation_get);
static void _gb_operation_destroy(struct kref *kref)
{
struct gb_operation *operation;
- unsigned long flags;
operation = container_of(kref, struct gb_operation, kref);
/* XXX Make sure it's not in flight */
- spin_lock_irqsave(&gb_operations_lock, flags);
list_del(&operation->links);
- spin_unlock_irqrestore(&gb_operations_lock, flags);
+ spin_unlock(&gb_operations_lock);
if (operation->response)
gb_operation_message_free(operation->response);
@@ -550,8 +548,11 @@ static void _gb_operation_destroy(struct kref *kref)
*/
void gb_operation_put(struct gb_operation *operation)
{
- if (!WARN_ON(!operation))
- kref_put(&operation->kref, _gb_operation_destroy);
+ if (WARN_ON(!operation))
+ return;
+
+ kref_put_spinlock_irqsave(&operation->kref, _gb_operation_destroy,
+ &gb_operations_lock);
}
EXPORT_SYMBOL_GPL(gb_operation_put);