]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
greybus: operation: fix operation-destroy race
authorJohan Hovold <johan@hovoldconsulting.com>
Thu, 9 Jul 2015 13:17:58 +0000 (15:17 +0200)
committerGreg Kroah-Hartman <gregkh@google.com>
Mon, 13 Jul 2015 22:29:27 +0000 (15:29 -0700)
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>
drivers/staging/greybus/operation.c

index 9e2ff7dd278ac07eba850fc8b4460130e36bba7a..f8d7df9ad3c48c8a3fac8f5135d726ead1934912 100644 (file)
@@ -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);