Merge tag 'drm-next-2021-11-12' of git://anongit.freedesktop.org/drm/drm
[linux-2.6-microblaze.git] / drivers / dma-buf / dma-buf.c
index 2ea59cb..6437b2e 100644 (file)
@@ -67,12 +67,9 @@ static void dma_buf_release(struct dentry *dentry)
        BUG_ON(dmabuf->vmapping_counter);
 
        /*
-        * Any fences that a dma-buf poll can wait on should be signaled
-        * before releasing dma-buf. This is the responsibility of each
-        * driver that uses the reservation objects.
-        *
-        * If you hit this BUG() it means someone dropped their ref to the
-        * dma-buf while still having pending operation to the buffer.
+        * If you hit this BUG() it could mean:
+        * * There's a file reference imbalance in dma_buf_poll / dma_buf_poll_cb or somewhere else
+        * * dmabuf->cb_in/out.active are non-0 despite no pending fence callback
         */
        BUG_ON(dmabuf->cb_in.active || dmabuf->cb_out.active);
 
@@ -200,6 +197,7 @@ static loff_t dma_buf_llseek(struct file *file, loff_t offset, int whence)
 static void dma_buf_poll_cb(struct dma_fence *fence, struct dma_fence_cb *cb)
 {
        struct dma_buf_poll_cb_t *dcb = (struct dma_buf_poll_cb_t *)cb;
+       struct dma_buf *dmabuf = container_of(dcb->poll, struct dma_buf, poll);
        unsigned long flags;
 
        spin_lock_irqsave(&dcb->poll->lock, flags);
@@ -207,21 +205,18 @@ static void dma_buf_poll_cb(struct dma_fence *fence, struct dma_fence_cb *cb)
        dcb->active = 0;
        spin_unlock_irqrestore(&dcb->poll->lock, flags);
        dma_fence_put(fence);
+       /* Paired with get_file in dma_buf_poll */
+       fput(dmabuf->file);
 }
 
-static bool dma_buf_poll_shared(struct dma_resv *resv,
+static bool dma_buf_poll_add_cb(struct dma_resv *resv, bool write,
                                struct dma_buf_poll_cb_t *dcb)
 {
-       struct dma_resv_list *fobj = dma_resv_shared_list(resv);
+       struct dma_resv_iter cursor;
        struct dma_fence *fence;
-       int i, r;
-
-       if (!fobj)
-               return false;
+       int r;
 
-       for (i = 0; i < fobj->shared_count; ++i) {
-               fence = rcu_dereference_protected(fobj->shared[i],
-                                                 dma_resv_held(resv));
+       dma_resv_for_each_fence(&cursor, resv, write, fence) {
                dma_fence_get(fence);
                r = dma_fence_add_callback(fence, &dcb->cb, dma_buf_poll_cb);
                if (!r)
@@ -232,24 +227,6 @@ static bool dma_buf_poll_shared(struct dma_resv *resv,
        return false;
 }
 
-static bool dma_buf_poll_excl(struct dma_resv *resv,
-                             struct dma_buf_poll_cb_t *dcb)
-{
-       struct dma_fence *fence = dma_resv_excl_fence(resv);
-       int r;
-
-       if (!fence)
-               return false;
-
-       dma_fence_get(fence);
-       r = dma_fence_add_callback(fence, &dcb->cb, dma_buf_poll_cb);
-       if (!r)
-               return true;
-       dma_fence_put(fence);
-
-       return false;
-}
-
 static __poll_t dma_buf_poll(struct file *file, poll_table *poll)
 {
        struct dma_buf *dmabuf;
@@ -282,8 +259,10 @@ static __poll_t dma_buf_poll(struct file *file, poll_table *poll)
                spin_unlock_irq(&dmabuf->poll.lock);
 
                if (events & EPOLLOUT) {
-                       if (!dma_buf_poll_shared(resv, dcb) &&
-                           !dma_buf_poll_excl(resv, dcb))
+                       /* Paired with fput in dma_buf_poll_cb */
+                       get_file(dmabuf->file);
+
+                       if (!dma_buf_poll_add_cb(resv, true, dcb))
                                /* No callback queued, wake up any other waiters */
                                dma_buf_poll_cb(NULL, &dcb->cb);
                        else
@@ -303,7 +282,10 @@ static __poll_t dma_buf_poll(struct file *file, poll_table *poll)
                spin_unlock_irq(&dmabuf->poll.lock);
 
                if (events & EPOLLIN) {
-                       if (!dma_buf_poll_excl(resv, dcb))
+                       /* Paired with fput in dma_buf_poll_cb */
+                       get_file(dmabuf->file);
+
+                       if (!dma_buf_poll_add_cb(resv, false, dcb))
                                /* No callback queued, wake up any other waiters */
                                dma_buf_poll_cb(NULL, &dcb->cb);
                        else
@@ -1356,10 +1338,9 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused)
 {
        struct dma_buf *buf_obj;
        struct dma_buf_attachment *attach_obj;
-       struct dma_resv *robj;
-       struct dma_resv_list *fobj;
+       struct dma_resv_iter cursor;
        struct dma_fence *fence;
-       int count = 0, attach_count, shared_count, i;
+       int count = 0, attach_count;
        size_t size = 0;
        int ret;
 
@@ -1378,6 +1359,8 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused)
                if (ret)
                        goto error_unlock;
 
+
+               spin_lock(&buf_obj->name_lock);
                seq_printf(s, "%08zu\t%08x\t%08x\t%08ld\t%s\t%08lu\t%s\n",
                                buf_obj->size,
                                buf_obj->file->f_flags, buf_obj->file->f_mode,
@@ -1385,22 +1368,12 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused)
                                buf_obj->exp_name,
                                file_inode(buf_obj->file)->i_ino,
                                buf_obj->name ?: "");
+               spin_unlock(&buf_obj->name_lock);
 
-               robj = buf_obj->resv;
-               fence = dma_resv_excl_fence(robj);
-               if (fence)
-                       seq_printf(s, "\tExclusive fence: %s %s %ssignalled\n",
-                                  fence->ops->get_driver_name(fence),
-                                  fence->ops->get_timeline_name(fence),
-                                  dma_fence_is_signaled(fence) ? "" : "un");
-
-               fobj = rcu_dereference_protected(robj->fence,
-                                                dma_resv_held(robj));
-               shared_count = fobj ? fobj->shared_count : 0;
-               for (i = 0; i < shared_count; i++) {
-                       fence = rcu_dereference_protected(fobj->shared[i],
-                                                         dma_resv_held(robj));
-                       seq_printf(s, "\tShared fence: %s %s %ssignalled\n",
+               dma_resv_for_each_fence(&cursor, buf_obj->resv, true, fence) {
+                       seq_printf(s, "\t%s fence: %s %s %ssignalled\n",
+                                  dma_resv_iter_is_exclusive(&cursor) ?
+                                       "Exclusive" : "Shared",
                                   fence->ops->get_driver_name(fence),
                                   fence->ops->get_timeline_name(fence),
                                   dma_fence_is_signaled(fence) ? "" : "un");