| 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; |