sync: allow async waits to be canceled

In order to allow drivers to cleanly handled teardown we need to allow them
to cancel pending async waits.  To do this cleanly, we move allocation of
sync_fence_waiter to the driver calling sync_async_wait().

Change-Id: Ifcd95648be6ec07026d67f810070a4310f099989
Signed-off-by: Erik Gilling <konkers@android.com>
diff --git a/drivers/base/sync.c b/drivers/base/sync.c
index cc40e4c..5e89195 100644
--- a/drivers/base/sync.c
+++ b/drivers/base/sync.c
@@ -421,33 +421,22 @@
 				container_of(pos, struct sync_fence_waiter,
 					     waiter_list);
 
-			waiter->callback(fence, waiter->callback_data);
 			list_del(pos);
-			kfree(waiter);
+			waiter->callback(fence, waiter);
 		}
 		wake_up(&fence->wq);
 	}
 }
 
 int sync_fence_wait_async(struct sync_fence *fence,
-			  void (*callback)(struct sync_fence *, void *data),
-			  void *callback_data)
+			  struct sync_fence_waiter *waiter)
 {
-	struct sync_fence_waiter *waiter;
 	unsigned long flags;
 	int err = 0;
 
-	waiter = kzalloc(sizeof(struct sync_fence_waiter), GFP_KERNEL);
-	if (waiter == NULL)
-		return -ENOMEM;
-
-	waiter->callback = callback;
-	waiter->callback_data = callback_data;
-
 	spin_lock_irqsave(&fence->waiter_list_lock, flags);
 
 	if (fence->status) {
-		kfree(waiter);
 		err = fence->status;
 		goto out;
 	}
@@ -459,6 +448,34 @@
 	return err;
 }
 
+int sync_fence_cancel_async(struct sync_fence *fence,
+			     struct sync_fence_waiter *waiter)
+{
+	struct list_head *pos;
+	struct list_head *n;
+	unsigned long flags;
+	int ret = -ENOENT;
+
+	spin_lock_irqsave(&fence->waiter_list_lock, flags);
+	/*
+	 * Make sure waiter is still in waiter_list because it is possible for
+	 * the waiter to be removed from the list while the callback is still
+	 * pending.
+	 */
+	list_for_each_safe(pos, n, &fence->waiter_list_head) {
+		struct sync_fence_waiter *list_waiter =
+			container_of(pos, struct sync_fence_waiter,
+				     waiter_list);
+		if (list_waiter == waiter) {
+			list_del(pos);
+			ret = 0;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&fence->waiter_list_lock, flags);
+	return ret;
+}
+
 int sync_fence_wait(struct sync_fence *fence, long timeout)
 {
 	int err;
@@ -739,8 +756,7 @@
 			container_of(pos, struct sync_fence_waiter,
 				     waiter_list);
 
-		seq_printf(s, "waiter %pF %p\n", waiter->callback,
-			   waiter->callback_data);
+		seq_printf(s, "waiter %pF\n", waiter->callback);
 	}
 	spin_unlock_irqrestore(&fence->waiter_list_lock, flags);
 }