operation->callback(operation);
        else
                complete_all(&operation->completion);
+       gb_operation_put(operation);
 }
 
 /*
                                        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.
  */
        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))
                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);
 
 
 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)
 {