greybus: operation: fix operation look-up race
authorJohan Hovold <johan@hovoldconsulting.com>
Tue, 14 Jul 2015 13:43:33 +0000 (15:43 +0200)
committerGreg Kroah-Hartman <gregkh@google.com>
Wed, 15 Jul 2015 19:39:13 +0000 (12:39 -0700)
Make sure to fully initialise the operation before adding it to the
active list when sending a request.

The operation should be fully initialised before adding it to the active
list to avoid racing with operation look up when receiving a response,
something which could potentially lead to a match against some earlier
(or intermediate) value of the id field.

Signed-off-by: Johan Hovold <johan@hovoldconsulting.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/operation.c

index 5cd4665c645cf7c5f4857501a1f594bf9a43954a..f7b0aa970bbcdd70e3182516f8b43e6ee3515c09 100644 (file)
@@ -642,16 +642,6 @@ int gb_operation_request_send(struct gb_operation *operation,
 
        if (!callback)
                return -EINVAL;
-
-       /*
-        * First, get an extra reference on the operation.
-        * It'll be dropped when the operation completes.
-        */
-       gb_operation_get(operation);
-       ret = gb_operation_get_active(operation);
-       if (ret)
-               goto err_put;
-
        /*
         * Record the callback function, which is executed in
         * non-atomic (workqueue) context when the final result
@@ -668,9 +658,17 @@ int gb_operation_request_send(struct gb_operation *operation,
        header = operation->request->header;
        header->operation_id = cpu_to_le16(operation->id);
 
-       /* All set, send the request */
        gb_operation_result_set(operation, -EINPROGRESS);
 
+       /*
+        * Get an extra reference on the operation. It'll be dropped when the
+        * operation completes.
+        */
+       gb_operation_get(operation);
+       ret = gb_operation_get_active(operation);
+       if (ret)
+               goto err_put;
+
        ret = gb_message_send(operation->request, gfp);
        if (ret)
                goto err_put_active;