From: Johan Hovold Date: Thu, 9 Jul 2015 13:17:58 +0000 (+0200) Subject: greybus: operation: fix operation-destroy race X-Git-Tag: v4.9-rc1~119^2~378^2~21^2~1398 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=85109f7ddde4b1842bfb08741a8b461e31ef2c4f;p=karo-tx-linux.git 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 Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- 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);