From deb4b9efb30606b8cb1150b8ae1e922405f60f8d Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 21 Nov 2014 19:29:15 -0600 Subject: [PATCH] greybus: add a reference to pending operations Grab an extra reference to an operation before sending it. Drop that reference at the end of its completion handling. It turns out gb_operation_get() got deleted along the way, so this re-introduces it. We're assuming we only get a reference when there's at least one in existence so we don't need a semaphore to protect it. Emphasize this by *not* returning a pointer to the referenced operation. Signed-off-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/operation.c | 21 +++++++++++++++++---- drivers/staging/greybus/operation.h | 2 +- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/staging/greybus/operation.c b/drivers/staging/greybus/operation.c index 9ad714eb773c..ab27cd94880a 100644 --- a/drivers/staging/greybus/operation.c +++ b/drivers/staging/greybus/operation.c @@ -157,6 +157,7 @@ static void gb_operation_complete(struct gb_operation *operation) operation->callback(operation); else complete_all(&operation->completion); + gb_operation_put(operation); } /* @@ -409,6 +410,14 @@ gb_operation_create_incoming(struct gb_connection *connection, request_size, response_size); } +/* + * Get an additional reference on an operation. + */ +void gb_operation_get(struct gb_operation *operation) +{ + kref_get(&operation->kref); +} + /* * Destroy a previously created operation. */ @@ -429,6 +438,10 @@ static void _gb_operation_destroy(struct kref *kref) kmem_cache_free(gb_operation_cache, operation); } +/* + * Drop a reference on an operation, and destroy it when the last + * one is gone. + */ void gb_operation_put(struct gb_operation *operation) { if (!WARN_ON(!operation)) @@ -454,11 +467,11 @@ int gb_operation_request_send(struct gb_operation *operation, return -ENOTCONN; /* - * XXX - * I think the order of operations is going to be - * significant, and if so, we may need a mutex to surround - * setting the operation id and submitting the buffer. + * First, get an extra reference on the operation. + * It'll be dropped when the operation completes. */ + gb_operation_get(operation); + operation->callback = callback; gb_pending_operation_insert(operation); diff --git a/drivers/staging/greybus/operation.h b/drivers/staging/greybus/operation.h index f60884455f4b..befce156aa67 100644 --- a/drivers/staging/greybus/operation.h +++ b/drivers/staging/greybus/operation.h @@ -88,7 +88,7 @@ void gb_connection_recv(struct gb_connection *connection, struct gb_operation *gb_operation_create(struct gb_connection *connection, u8 type, size_t request_size, size_t response_size); -struct gb_operation *gb_operation_get(struct gb_operation *operation); +void gb_operation_get(struct gb_operation *operation); void gb_operation_put(struct gb_operation *operation); static inline void gb_operation_destroy(struct gb_operation *operation) {