greybus: operation: add active counter
authorJohan Hovold <johan@hovoldconsulting.com>
Tue, 14 Jul 2015 13:43:25 +0000 (15:43 +0200)
committerGreg Kroah-Hartman <gregkh@google.com>
Wed, 15 Jul 2015 19:39:13 +0000 (12:39 -0700)
Add active counter to track operations that are in use.

Note that the active count is always less than the reference count.

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

index 081694c..abe44c1 100644 (file)
@@ -32,6 +32,18 @@ static DEFINE_SPINLOCK(gb_operations_lock);
 static int gb_operation_response_send(struct gb_operation *operation,
                                        int errno);
 
+/* Caller holds operation reference. */
+static inline void gb_operation_get_active(struct gb_operation *operation)
+{
+       atomic_inc(&operation->active);
+}
+
+/* Caller holds operation reference. */
+static inline void gb_operation_put_active(struct gb_operation *operation)
+{
+       atomic_dec(&operation->active);
+}
+
 /*
  * Set an operation's result.
  *
@@ -204,6 +216,7 @@ static void gb_operation_work(struct work_struct *work)
 
        operation->callback(operation);
 
+       gb_operation_put_active(operation);
        gb_operation_put(operation);
 }
 
@@ -449,6 +462,7 @@ gb_operation_create_common(struct gb_connection *connection, u8 type,
        INIT_WORK(&operation->work, gb_operation_work);
        init_completion(&operation->completion);
        kref_init(&operation->kref);
+       atomic_set(&operation->active, 0);
 
        spin_lock_irqsave(&gb_operations_lock, flags);
        list_add_tail(&operation->links, &connection->operations);
@@ -597,6 +611,7 @@ int gb_operation_request_send(struct gb_operation *operation,
         * It'll be dropped when the operation completes.
         */
        gb_operation_get(operation);
+       gb_operation_get_active(operation);
 
        /*
         * Record the callback function, which is executed in
@@ -618,8 +633,10 @@ int gb_operation_request_send(struct gb_operation *operation,
        gb_operation_result_set(operation, -EINPROGRESS);
 
        ret = gb_message_send(operation->request, gfp);
-       if (ret)
+       if (ret) {
+               gb_operation_put_active(operation);
                gb_operation_put(operation);
+       }
 
        return ret;
 }
@@ -688,13 +705,16 @@ static int gb_operation_response_send(struct gb_operation *operation,
 
        /* Reference will be dropped when message has been sent. */
        gb_operation_get(operation);
+       gb_operation_get_active(operation);
 
        /* Fill in the response header and send it */
        operation->response->header->result = gb_operation_errno_map(errno);
 
        ret = gb_message_send(operation->response, GFP_KERNEL);
-       if (ret)
+       if (ret) {
+               gb_operation_put_active(operation);
                gb_operation_put(operation);
+       }
 
        return ret;
 }
@@ -723,6 +743,7 @@ void greybus_message_sent(struct greybus_host_device *hd,
                        dev_err(&operation->connection->dev,
                                "error sending response: %d\n", status);
                }
+               gb_operation_put_active(operation);
                gb_operation_put(operation);
        } else if (status) {
                if (gb_operation_result_set(operation, status))
@@ -751,6 +772,8 @@ static void gb_connection_recv_request(struct gb_connection *connection,
                return;         /* XXX Respond with pre-allocated ENOMEM */
        }
 
+       gb_operation_get_active(operation);
+
        /*
         * Incoming requests are handled by arranging for the
         * request handler to be the operation's callback function.
@@ -863,6 +886,7 @@ void gb_operation_cancel(struct gb_operation *operation, int errno)
        } else {
                if (gb_operation_result_set(operation, errno)) {
                        gb_message_cancel(operation->request);
+                       gb_operation_put_active(operation);
                        gb_operation_put(operation);
                }
        }
index c16f64d..b323866 100644 (file)
@@ -127,6 +127,8 @@ struct gb_operation {
        struct completion       completion;
 
        struct kref             kref;
+       atomic_t                active;
+
        struct list_head        links;          /* connection->operations */
 };