msm: camera: sync: protect sync obj creation from race condition

Multiple thread can find the same sync obj and waiting for lock.
If the spinlock releases after another thread finds a sync obj,
there is possibility that they will get the same id. Use atomic
operation to ensure obj is free.

Change-Id: I1d3c40f2c0315d27ecf11b953a3c9bdb89d41ef8
Signed-off-by: Junzhe Zou <jnzhezou@codeaurora.org>
diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
index 37d612b..2422016 100644
--- a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
+++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
@@ -25,22 +25,25 @@
 {
 	int rc;
 	long idx;
+	bool bit;
 
 	do {
 		idx = find_first_zero_bit(sync_dev->bitmap, CAM_SYNC_MAX_OBJS);
 		if (idx >= CAM_SYNC_MAX_OBJS)
 			return -ENOMEM;
-	} while (!spin_trylock_bh(&sync_dev->row_spinlocks[idx]));
+		bit = test_and_set_bit(idx, sync_dev->bitmap);
+	} while (bit);
 
+	spin_lock_bh(&sync_dev->row_spinlocks[idx]);
 	rc = cam_sync_init_object(sync_dev->sync_table, idx, name);
 	if (rc) {
 		CAM_ERR(CAM_SYNC, "Error: Unable to init row at idx = %ld",
 			idx);
+		clear_bit(idx, sync_dev->bitmap);
 		spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
 		return -EINVAL;
 	}
 
-	set_bit(idx, sync_dev->bitmap);
 	*sync_obj = idx;
 	spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
 
@@ -299,6 +302,7 @@
 {
 	int rc;
 	long idx = 0;
+	bool bit;
 
 	if (!sync_obj || !merged_obj) {
 		CAM_ERR(CAM_SYNC, "Invalid pointer(s)");
@@ -316,9 +320,10 @@
 		idx = find_first_zero_bit(sync_dev->bitmap, CAM_SYNC_MAX_OBJS);
 		if (idx >= CAM_SYNC_MAX_OBJS)
 			return -ENOMEM;
-	} while (!spin_trylock_bh(&sync_dev->row_spinlocks[idx]));
+		bit = test_and_set_bit(idx, sync_dev->bitmap);
+	} while (bit);
 
-	set_bit(idx, sync_dev->bitmap);
+	spin_lock_bh(&sync_dev->row_spinlocks[idx]);
 
 	rc = cam_sync_init_group_object(sync_dev->sync_table,
 		idx, sync_obj,
@@ -326,6 +331,7 @@
 	if (rc < 0) {
 		CAM_ERR(CAM_SYNC, "Error: Unable to init row at idx = %ld",
 			idx);
+		clear_bit(idx, sync_dev->bitmap);
 		spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
 		return -EINVAL;
 	}