diff --git a/drivers/staging/greybus/operation.c b/drivers/staging/greybus/operation.c index bc68a5f9be66..2b33d336bfad 100644 --- a/drivers/staging/greybus/operation.c +++ b/drivers/staging/greybus/operation.c @@ -274,6 +274,7 @@ struct gb_operation *gb_operation_create(struct gb_connection *connection, operation->callback = NULL; /* set at submit time */ init_completion(&operation->completion); INIT_DELAYED_WORK(&operation->timeout_work, operation_timeout); + kref_init(&operation->kref); spin_lock_irq(&gb_operations_lock); list_add_tail(&operation->links, &connection->operations); @@ -292,10 +293,11 @@ struct gb_operation *gb_operation_create(struct gb_connection *connection, /* * Destroy a previously created operation. */ -void gb_operation_destroy(struct gb_operation *operation) +static void _gb_operation_destroy(struct kref *kref) { - if (WARN_ON(!operation)) - return; + struct gb_operation *operation; + + operation = container_of(kref, struct gb_operation, kref); /* XXX Make sure it's not in flight */ spin_lock_irq(&gb_operations_lock); @@ -308,6 +310,12 @@ void gb_operation_destroy(struct gb_operation *operation) kmem_cache_free(gb_operation_cache, operation); } +void gb_operation_put(struct gb_operation *operation) +{ + if (!WARN_ON(!operation)) + kref_put(&operation->kref, _gb_operation_destroy); +} + /* * Send an operation request message. The caller has filled in * any payload so the request message is ready to go. If non-null, diff --git a/drivers/staging/greybus/operation.h b/drivers/staging/greybus/operation.h index f30b162f78b7..dc15c2f61e30 100644 --- a/drivers/staging/greybus/operation.h +++ b/drivers/staging/greybus/operation.h @@ -65,6 +65,7 @@ struct gb_operation { struct completion completion; /* Used if no callback */ struct delayed_work timeout_work; + struct kref kref; struct list_head links; /* connection->{operations,pending} */ /* These are what's used by caller */ @@ -78,7 +79,12 @@ void gb_connection_operation_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); -void gb_operation_destroy(struct gb_operation *operation); +struct gb_operation *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) +{ + gb_operation_put(operation); +} int gb_operation_request_send(struct gb_operation *operation, gb_operation_callback callback);