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 <elder@linaro.org>
Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
diff --git a/drivers/staging/greybus/operation.c b/drivers/staging/greybus/operation.c
index 9ad714e..ab27cd9 100644
--- a/drivers/staging/greybus/operation.c
+++ b/drivers/staging/greybus/operation.c
@@ -157,6 +157,7 @@
 		operation->callback(operation);
 	else
 		complete_all(&operation->completion);
+	gb_operation_put(operation);
 }
 
 /*
@@ -410,6 +411,14 @@
 }
 
 /*
+ * Get an additional reference on an operation.
+ */
+void gb_operation_get(struct gb_operation *operation)
+{
+	kref_get(&operation->kref);
+}
+
+/*
  * Destroy a previously created operation.
  */
 static void _gb_operation_destroy(struct kref *kref)
@@ -429,6 +438,10 @@
 	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 @@
 		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 f608844..befce15 100644
--- a/drivers/staging/greybus/operation.h
+++ b/drivers/staging/greybus/operation.h
@@ -88,7 +88,7 @@
 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)
 {