Skip to content

Commit

Permalink
reservation: add suppport for read-only access using rcu
Browse files Browse the repository at this point in the history
This adds some extra functions to deal with rcu.

reservation_object_get_fences_rcu() will obtain the list of shared
and exclusive fences without obtaining the ww_mutex.

reservation_object_wait_timeout_rcu() will wait on all fences of the
reservation_object, without obtaining the ww_mutex.

reservation_object_test_signaled_rcu() will test if all fences of the
reservation_object are signaled without using the ww_mutex.

reservation_object_get_excl and reservation_object_get_list require
the reservation object to be held, updating requires
write_seqcount_begin/end. If only the exclusive fence is needed,
rcu_dereference followed by fence_get_rcu can be used, if the shared
fences are needed it's recommended to use the supplied functions.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@canonical.com>
Acked-by: Sumit Semwal <sumit.semwal@linaro.org>
Acked-by: Daniel Vetter <daniel@ffwll.ch>
Reviewed-By: Thomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Maarten Lankhorst authored and Greg Kroah-Hartman committed Jul 8, 2014
1 parent 04a5faa commit 3c3b177
Show file tree
Hide file tree
Showing 5 changed files with 400 additions and 54 deletions.
47 changes: 36 additions & 11 deletions drivers/dma-buf/dma-buf.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ static unsigned int dma_buf_poll(struct file *file, poll_table *poll)
struct reservation_object_list *fobj;
struct fence *fence_excl;
unsigned long events;
unsigned shared_count;
unsigned shared_count, seq;

dmabuf = file->private_data;
if (!dmabuf || !dmabuf->resv)
Expand All @@ -151,14 +151,20 @@ static unsigned int dma_buf_poll(struct file *file, poll_table *poll)
if (!events)
return 0;

ww_mutex_lock(&resv->lock, NULL);
retry:
seq = read_seqcount_begin(&resv->seq);
rcu_read_lock();

fobj = resv->fence;
if (!fobj)
goto out;

shared_count = fobj->shared_count;
fence_excl = resv->fence_excl;
fobj = rcu_dereference(resv->fence);
if (fobj)
shared_count = fobj->shared_count;
else
shared_count = 0;
fence_excl = rcu_dereference(resv->fence_excl);
if (read_seqcount_retry(&resv->seq, seq)) {
rcu_read_unlock();
goto retry;
}

if (fence_excl && (!(events & POLLOUT) || shared_count == 0)) {
struct dma_buf_poll_cb_t *dcb = &dmabuf->cb_excl;
Expand All @@ -176,14 +182,20 @@ static unsigned int dma_buf_poll(struct file *file, poll_table *poll)
spin_unlock_irq(&dmabuf->poll.lock);

if (events & pevents) {
if (!fence_add_callback(fence_excl, &dcb->cb,
if (!fence_get_rcu(fence_excl)) {
/* force a recheck */
events &= ~pevents;
dma_buf_poll_cb(NULL, &dcb->cb);
} else if (!fence_add_callback(fence_excl, &dcb->cb,
dma_buf_poll_cb)) {
events &= ~pevents;
fence_put(fence_excl);
} else {
/*
* No callback queued, wake up any additional
* waiters.
*/
fence_put(fence_excl);
dma_buf_poll_cb(NULL, &dcb->cb);
}
}
Expand All @@ -205,13 +217,26 @@ static unsigned int dma_buf_poll(struct file *file, poll_table *poll)
goto out;

for (i = 0; i < shared_count; ++i) {
struct fence *fence = fobj->shared[i];
struct fence *fence = rcu_dereference(fobj->shared[i]);

if (!fence_get_rcu(fence)) {
/*
* fence refcount dropped to zero, this means
* that fobj has been freed
*
* call dma_buf_poll_cb and force a recheck!
*/
events &= ~POLLOUT;
dma_buf_poll_cb(NULL, &dcb->cb);
break;
}
if (!fence_add_callback(fence, &dcb->cb,
dma_buf_poll_cb)) {
fence_put(fence);
events &= ~POLLOUT;
break;
}
fence_put(fence);
}

/* No callback queued, wake up any additional waiters. */
Expand All @@ -220,7 +245,7 @@ static unsigned int dma_buf_poll(struct file *file, poll_table *poll)
}

out:
ww_mutex_unlock(&resv->lock);
rcu_read_unlock();
return events;
}

Expand Down
2 changes: 1 addition & 1 deletion drivers/dma-buf/fence.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ EXPORT_SYMBOL(fence_release);

void fence_free(struct fence *fence)
{
kfree(fence);
kfree_rcu(fence, rcu);
}
EXPORT_SYMBOL(fence_free);

Expand Down
Loading

0 comments on commit 3c3b177

Please sign in to comment.