summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorInki Dae <inki.dae@samsung.com>2014-11-25 09:01:36 (GMT)
committerChanho Park <chanho61.park@samsung.com>2014-11-25 11:20:32 (GMT)
commit135b72a7be9a484e8e2576bf3c49a51445b76bce (patch)
tree1fcd3dbb5b25255795f73c1076805a1c7e8e215a
parent8c34dbd28cfce4e09ebec8bdf1b820924c2df45b (diff)
downloadlinux-3.10-135b72a7be9a484e8e2576bf3c49a51445b76bce.zip
linux-3.10-135b72a7be9a484e8e2576bf3c49a51445b76bce.tar.gz
linux-3.10-135b72a7be9a484e8e2576bf3c49a51445b76bce.tar.bz2
This patch adds dmabuf_sync_reference_reservation function that can get/drop a reference to all fences added to reservation_object of a given dmabuf object, and calls it before blocked and after waked up to avoid null pointer dereference. Change-Id: I32f31b5a54e233d4a06b9915d26b04cda4e31d01 Signed-off-by: Inki Dae <inki.dae@samsung.com>
-rw-r--r--drivers/dma-buf/dmabuf-sync.c46
1 files changed, 46 insertions, 0 deletions
diff --git a/drivers/dma-buf/dmabuf-sync.c b/drivers/dma-buf/dmabuf-sync.c
index 5f51e17..d654669 100644
--- a/drivers/dma-buf/dmabuf-sync.c
+++ b/drivers/dma-buf/dmabuf-sync.c
@@ -608,6 +608,47 @@ out:
spin_unlock_irqrestore(&orders_lock, o_flags);
}
+static void dmabuf_sync_reference_reservation(struct dma_buf *dmabuf,
+ bool reference)
+{
+ struct reservation_object *obj = dmabuf->resv;
+ struct reservation_object_list *fobj;
+ struct fence *fence;
+
+ rcu_read_lock();
+
+ fobj = rcu_dereference(obj->fence);
+ if (fobj) {
+ int i;
+
+ for (i = 0; i < fobj->shared_count; i++) {
+ fence = rcu_dereference(fobj->shared[i]);
+ if (!fence) {
+ WARN_ON(1);
+ continue;
+ }
+
+ if (reference)
+ fence_get_rcu(fence);
+ else
+ fence_put(fence);
+ }
+ }
+
+ fence = rcu_dereference(obj->fence_excl);
+ if (!fence) {
+ rcu_read_unlock();
+ return;
+ }
+
+ if (reference)
+ fence_get_rcu(fence);
+ else
+ fence_put(fence);
+
+ rcu_read_unlock();
+}
+
/*
* is_higher_priority_than_current - check if a given sobj was requested
* the first.
@@ -690,6 +731,7 @@ long dmabuf_sync_wait_all(struct dmabuf_sync *sync)
sf = sobj->sfence;
dmabuf = sobj->dmabuf;
+ dmabuf_sync_reference_reservation(dmabuf, true);
/*
* It doesn't need to wait for other thread or threads
@@ -730,6 +772,7 @@ go_back_to_wait:
out_enable_signal:
fence_enable_sw_signaling(&sf->base);
dmabuf_sync_update(sobj);
+ dmabuf_sync_reference_reservation(dmabuf, false);
dmabuf_sync_cache_ops(sobj);
spin_lock_irqsave(&sync->lock, s_flags);
@@ -788,6 +831,8 @@ long dmabuf_sync_wait(struct dma_buf *dmabuf, unsigned int ctx,
sobj_get(sobj);
spin_unlock_irqrestore(&orders_lock, o_flags);
+ dmabuf_sync_reference_reservation(dmabuf, true);
+
/*
* It doesn't need to wait for other thread or threads
* if there is no any sync object which has higher priority
@@ -827,6 +872,7 @@ go_back_to_wait:
out_enable_signal:
fence_enable_sw_signaling(&sync->sfence.base);
dmabuf_sync_update(sobj);
+ dmabuf_sync_reference_reservation(dmabuf, false);
dmabuf_sync_cache_ops(sobj);
return timeout;