summaryrefslogtreecommitdiffstats
path: root/drivers/staging/greybus/operation.c
diff options
context:
space:
mode:
authorJohan Hovold <johan@hovoldconsulting.com>2015-07-14 15:43:25 +0200
committerGreg Kroah-Hartman <gregkh@google.com>2015-07-15 12:39:13 -0700
commit3eeac7e37ce9856e53693772dfe81a79b57b5a00 (patch)
tree0823f523632ace05cd73c3c04d05b6dd974196fa /drivers/staging/greybus/operation.c
parent9a586bd2bb80a268345cc8ccfa702413359ece06 (diff)
greybus: operation: add active counter
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>
Diffstat (limited to 'drivers/staging/greybus/operation.c')
-rw-r--r--drivers/staging/greybus/operation.c28
1 files changed, 26 insertions, 2 deletions
diff --git a/drivers/staging/greybus/operation.c b/drivers/staging/greybus/operation.c
index 081694c8a1c2..abe44c18fb9e 100644
--- a/drivers/staging/greybus/operation.c
+++ b/drivers/staging/greybus/operation.c
@@ -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);
}
}