gpu: ion: Prevent deadlock with cache flushing
Cache flushing takes the mmap semaphore to validate the
address range. This can cause a deadlock in the following
scenario with two threads in the same client:
Thread 1 Thread 2
(cache operation) (mmap)
-----------------------------------------
lock(client_lock)
down_write(mmap_semaphore)
down_read(mmap_semaphore)
lock(client_lock)
Fix this by doing the check for the address range before
taking the client lock. This is independent of Ion so there
is no need to have this lock locked.
Change-Id: Ibe372cf232fbad7e031ab2d38cf3a34823f43bf9
Signed-off-by: Laura Abbott <lauraa@codeaurora.org>
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 60bc276..5a596a0 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -618,7 +618,6 @@
unsigned int cmd)
{
struct ion_buffer *buffer;
- unsigned long start, end;
int ret = -EINVAL;
mutex_lock(&client->lock);
@@ -643,14 +642,6 @@
goto out;
}
- start = (unsigned long) uaddr;
- end = (unsigned long) uaddr + len;
-
- if (check_vaddr_bounds(start, end)) {
- pr_err("%s: virtual address %p is out of bounds\n",
- __func__, uaddr);
- goto out;
- }
ret = buffer->heap->ops->cache_op(buffer->heap, buffer, uaddr,
offset, len, cmd);
@@ -1174,11 +1165,21 @@
case ION_IOC_CLEAN_INV_CACHES:
{
struct ion_flush_data data;
+ unsigned long start, end;
if (copy_from_user(&data, (void __user *)arg,
sizeof(struct ion_flush_data)))
return -EFAULT;
+ start = (unsigned long) data.vaddr;
+ end = (unsigned long) data.vaddr + data.length;
+
+ if (check_vaddr_bounds(start, end)) {
+ pr_err("%s: virtual address %p is out of bounds\n",
+ __func__, data.vaddr);
+ return -EINVAL;
+ }
+
return ion_do_cache_op(client, data.handle, data.vaddr,
data.offset, data.length, cmd);