drv: check if a bo has lost all references in a 2nd pass

The same buffer can back multiple planes with different offsets. Thus
when we dereference the bo, we have to check again after all planes are
dereferenced.

This change also adds a missing unlock on an asserted return pass in
drv_bo_mapping_destroy.

BUG=b:201767377
TEST=atest android.media.cts.DecodeAccuracyTest#testGLViewDecodeAccuracy

Change-Id: I9dabf2f9b7ed33c9ed2f45b8ae498e98bfb0fc03
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/minigbm/+/3203235
Commit-Queue: Yiwei Zhang <zzyiwei@chromium.org>
Commit-Queue: Chia-I Wu <olv@google.com>
Tested-by: Yiwei Zhang <zzyiwei@chromium.org>
Auto-Submit: Yiwei Zhang <zzyiwei@chromium.org>
Reviewed-by: Chia-I Wu <olv@google.com>
diff --git a/drv.c b/drv.c
index 39a6df2..ea979d3 100644
--- a/drv.c
+++ b/drv.c
@@ -262,6 +262,8 @@
 			if (!--mapping->vma->refcount) {
 				int ret = drv->backend->bo_unmap(bo, mapping->vma);
 				if (ret) {
+					pthread_mutex_unlock(&drv->mappings_lock);
+					assert(ret);
 					drv_log("munmap failed\n");
 					return;
 				}
@@ -302,24 +304,31 @@
 static bool drv_bo_release(struct bo *bo)
 {
 	struct driver *drv = bo->drv;
-	bool unreferenced = true;
+	uintptr_t num;
 
 	pthread_mutex_lock(&drv->buffer_table_lock);
 	for (size_t plane = 0; plane < bo->meta.num_planes; plane++) {
-		uintptr_t num = 0;
-
 		if (!drmHashLookup(drv->buffer_table, bo->handles[plane].u32, (void **)&num)) {
 			drmHashDelete(drv->buffer_table, bo->handles[plane].u32);
-		}
 
-		if (num > 1) {
-			drmHashInsert(drv->buffer_table, bo->handles[plane].u32, (void *)(num - 1));
-			unreferenced = false;
+			if (num > 1) {
+				drmHashInsert(drv->buffer_table, bo->handles[plane].u32,
+					      (void *)(num - 1));
+			}
+		}
+	}
+
+	/* The same buffer can back multiple planes with different offsets. */
+	for (size_t plane = 0; plane < bo->meta.num_planes; plane++) {
+		if (!drmHashLookup(drv->buffer_table, bo->handles[plane].u32, (void **)&num)) {
+			/* num is positive if found in the hashmap. */
+			pthread_mutex_unlock(&drv->buffer_table_lock);
+			return false;
 		}
 	}
 	pthread_mutex_unlock(&drv->buffer_table_lock);
 
-	return unreferenced;
+	return true;
 }
 
 struct bo *drv_bo_create(struct driver *drv, uint32_t width, uint32_t height, uint32_t format,