minigbm: unmap right before buffer destruction

Regardless of the allocator, we want to make sure any mappings
we create are eventually freed. This patch adds logic to
drv_bo_destroy to free any mappings before the GEM close
ioctl is called.

BUG=chromium:764871
TEST=gbmtest, mmap_test -g on eve

Change-Id: I8f4edb4bc01ff6e1d71a60e0309e77e9fc3840f4
Reviewed-on: https://chromium-review.googlesource.com/441916
Commit-Ready: Gurchetan Singh <gurchetansingh@chromium.org>
Tested-by: Gurchetan Singh <gurchetansingh@chromium.org>
Reviewed-by: Joe Kniss <djmk@google.com>
Reviewed-by: Stéphane Marchesin <marcheu@chromium.org>
Reviewed-by: Tomasz Figa <tfiga@chromium.org>
diff --git a/drv.c b/drv.c
index ff99893..b43b771 100644
--- a/drv.c
+++ b/drv.c
@@ -305,7 +305,6 @@
 {
 	size_t plane;
 	uintptr_t total = 0;
-	size_t map_count = 0;
 	struct driver *drv = bo->drv;
 
 	pthread_mutex_lock(&drv->driver_lock);
@@ -313,22 +312,13 @@
 	for (plane = 0; plane < bo->num_planes; plane++)
 		drv_decrement_reference_count(drv, bo, plane);
 
-	for (plane = 0; plane < bo->num_planes; plane++) {
-		void *ptr;
-
+	for (plane = 0; plane < bo->num_planes; plane++)
 		total += drv_get_reference_count(drv, bo, plane);
-		map_count += !drmHashLookup(bo->drv->map_table, bo->handles[plane].u32, &ptr);
-	}
 
 	pthread_mutex_unlock(&drv->driver_lock);
 
 	if (total == 0) {
-		/*
-		 * If we leak a reference to the GEM handle being freed here in the mapping table,
-		 * we risk using the mapping table entry later for a completely different BO that
-		 * gets the same handle. (See b/38250067.)
-		 */
-		assert(!map_count);
+		assert(drv_map_info_destroy(bo) == 0);
 		bo->drv->backend->bo_destroy(bo);
 	}
 
diff --git a/helpers.c b/helpers.c
index 9d72a6c..979521a 100644
--- a/helpers.c
+++ b/helpers.c
@@ -318,6 +318,35 @@
 	return munmap(data->addr, data->length);
 }
 
+int drv_map_info_destroy(struct bo *bo)
+{
+	int ret;
+	void *ptr;
+	size_t plane;
+	struct map_info *data;
+
+	/*
+	 * This function is called right before the buffer is destroyed. It will free any mappings
+	 * associated with the buffer.
+	 */
+
+	for (plane = 0; plane < bo->num_planes; plane++) {
+		if (!drmHashLookup(bo->drv->map_table, bo->handles[plane].u32, &ptr)) {
+			data = (struct map_info *)ptr;
+			ret = bo->drv->backend->bo_unmap(bo, data);
+			if (ret) {
+				fprintf(stderr, "drv: munmap failed");
+				return ret;
+			}
+
+			drmHashDelete(bo->drv->map_table, data->handle);
+			free(data);
+		}
+	}
+
+	return 0;
+}
+
 uintptr_t drv_get_reference_count(struct driver *drv, struct bo *bo, size_t plane)
 {
 	void *count;
diff --git a/helpers.h b/helpers.h
index b580643..0cc1a17 100644
--- a/helpers.h
+++ b/helpers.h
@@ -14,6 +14,7 @@
 int drv_dumb_bo_create(struct bo *bo, uint32_t width, uint32_t height, uint32_t format,
 		       uint32_t flags);
 int drv_dumb_bo_destroy(struct bo *bo);
+int drv_map_info_destroy(struct bo *bo);
 int drv_gem_bo_destroy(struct bo *bo);
 int drv_prime_bo_import(struct bo *bo, struct drv_import_fd_data *data);
 void *drv_dumb_bo_map(struct bo *bo, struct map_info *data, size_t plane, int prot);