blob: 3c4d198d3fcda16c0c1957b45a993e2f34029fc5 [file] [log] [blame]
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sandeep Patil <sspatil@google.com>
Date: Mon, 26 Aug 2019 22:46:07 -0700
Subject: ANDROID: staging: ion: add support for consistent heap ids
heap id is part of ION's UAPI. Since the heaps are now kernel modules,
the current scheme of incrementing the heap id for the next heap doesn't
work. For example, if one insert->remove->insert the system heap module,
the heap id associated with the system heap changes. This immediately
breaks all of userspace.
So, in order to fix this, we reserve first 16 heap ids for GKI heaps
and leave 16 more heap ids for any custom heap type that may exist.
Bug: 133508579
Test: ion-unit-test
Test: ion-unit-test (after removal and insertion of system heap module)
Change-Id: I8412e590263869e029151a017b072399f54206f0
Signed-off-by: Sandeep Patil <sspatil@google.com>
[maennich: Folded 5da9f3fe49d4 ("ANDROID: staging: ion: Fix
uninitialized variable warning") into this patch,
Folded 226a0a7161c3 ("ANDROID: staging: ion: Fix dynamic heap
ID assignment") into this patch]
Signed-off-by: Matthias Maennich <maennich@google.com>
---
drivers/staging/android/ion/ion.c | 76 ++++++++++++++++++++++-
drivers/staging/android/ion/ion_private.h | 5 +-
2 files changed, 77 insertions(+), 4 deletions(-)
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c
index 548d65dbd3ac..026a8fada480 100644
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -7,6 +7,7 @@
*
*/
+#include <linux/bitmap.h>
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/dma-buf.h>
@@ -27,7 +28,6 @@
#include "ion_private.h"
static struct ion_device *internal_dev;
-static int heap_id;
/* Entry into ION allocator for rest of the kernel */
struct dma_buf *ion_alloc(size_t len, unsigned int heap_id_mask,
@@ -222,6 +222,66 @@ static int debug_shrink_get(void *data, u64 *val)
DEFINE_SIMPLE_ATTRIBUTE(debug_shrink_fops, debug_shrink_get,
debug_shrink_set, "%llu\n");
+static int ion_assign_heap_id(struct ion_heap *heap, struct ion_device *dev)
+{
+ int id_bit = -EINVAL;
+ int start_bit = -1, end_bit = -1;
+
+ switch (heap->type) {
+ case ION_HEAP_TYPE_SYSTEM:
+ id_bit = __ffs(ION_HEAP_SYSTEM);
+ break;
+ case ION_HEAP_TYPE_SYSTEM_CONTIG:
+ id_bit = __ffs(ION_HEAP_SYSTEM_CONTIG);
+ break;
+ case ION_HEAP_TYPE_CHUNK:
+ id_bit = __ffs(ION_HEAP_CHUNK);
+ break;
+ case ION_HEAP_TYPE_CARVEOUT:
+ start_bit = __ffs(ION_HEAP_CARVEOUT_START);
+ end_bit = __ffs(ION_HEAP_CARVEOUT_END);
+ break;
+ case ION_HEAP_TYPE_DMA:
+ start_bit = __ffs(ION_HEAP_DMA_START);
+ end_bit = __ffs(ION_HEAP_DMA_END);
+ break;
+ case ION_HEAP_TYPE_CUSTOM ... ION_HEAP_TYPE_MAX:
+ start_bit = __ffs(ION_HEAP_CUSTOM_START);
+ end_bit = __ffs(ION_HEAP_CUSTOM_END);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* For carveout, dma & custom heaps, we first let the heaps choose their
+ * own IDs. This allows the old behaviour of knowing the heap ids
+ * of these type of heaps in advance in user space. If a heap with
+ * that ID already exists, it is an error.
+ *
+ * If the heap hasn't picked an id by itself, then we assign it
+ * one.
+ */
+ if (id_bit < 0) {
+ if (heap->id) {
+ id_bit = __ffs(heap->id);
+ if (id_bit < start_bit || id_bit > end_bit)
+ return -EINVAL;
+ } else {
+ id_bit = find_next_zero_bit(dev->heap_ids, end_bit + 1,
+ start_bit);
+ if (id_bit > end_bit)
+ return -ENOSPC;
+ }
+ }
+
+ if (test_and_set_bit(id_bit, dev->heap_ids))
+ return -EEXIST;
+ heap->id = id_bit;
+ dev->heap_cnt++;
+
+ return 0;
+}
+
int __ion_device_add_heap(struct ion_heap *heap, struct module *owner)
{
struct ion_device *dev = internal_dev;
@@ -283,7 +343,14 @@ int __ion_device_add_heap(struct ion_heap *heap, struct module *owner)
heap->debugfs_dir = heap_root;
down_write(&dev->lock);
- heap->id = heap_id++;
+ ret = ion_assign_heap_id(heap, dev);
+ if (ret) {
+ pr_err("%s: Failed to assign heap id for heap type %x\n",
+ __func__, heap->type);
+ up_write(&dev->lock);
+ goto out_debugfs_cleanup;
+ }
+
/*
* use negative heap->id to reverse the priority -- when traversing
* the list later attempt higher id numbers first
@@ -291,11 +358,12 @@ int __ion_device_add_heap(struct ion_heap *heap, struct module *owner)
plist_node_init(&heap->node, -heap->id);
plist_add(&heap->node, &dev->heaps);
- dev->heap_cnt++;
up_write(&dev->lock);
return 0;
+out_debugfs_cleanup:
+ debugfs_remove_recursive(heap->debugfs_dir);
out_heap_cleanup:
ion_heap_cleanup(heap);
out:
@@ -321,6 +389,8 @@ void ion_device_remove_heap(struct ion_heap *heap)
__func__, heap->name);
}
debugfs_remove_recursive(heap->debugfs_dir);
+ clear_bit(heap->id - 1, dev->heap_ids);
+ dev->heap_cnt--;
up_write(&dev->lock);
}
EXPORT_SYMBOL(ion_device_remove_heap);
diff --git a/drivers/staging/android/ion/ion_private.h b/drivers/staging/android/ion/ion_private.h
index 5cc09fbfbefe..2f5376e131c3 100644
--- a/drivers/staging/android/ion/ion_private.h
+++ b/drivers/staging/android/ion/ion_private.h
@@ -23,13 +23,16 @@
* @dev: the actual misc device
* @buffers: an rb tree of all the existing buffers
* @buffer_lock: lock protecting the tree of buffers
- * @lock: rwsem protecting the tree of heaps and clients
+ * @lock: rwsem protecting the tree of heaps, heap_bitmap and
+ * clients
+ * @heap_ids: bitmap of register heap ids
*/
struct ion_device {
struct miscdevice dev;
struct rb_root buffers;
struct mutex buffer_lock;
struct rw_semaphore lock;
+ DECLARE_BITMAP(heap_ids, ION_NUM_MAX_HEAPS);
struct plist_head heaps;
struct dentry *debug_root;
int heap_cnt;