]> Git Repo - linux.git/commitdiff
Merge tag 'drm-misc-fixes-2021-11-11' of git://anongit.freedesktop.org/drm/drm-misc...
authorDave Airlie <[email protected]>
Fri, 12 Nov 2021 03:06:37 +0000 (13:06 +1000)
committerDave Airlie <[email protected]>
Fri, 12 Nov 2021 03:06:41 +0000 (13:06 +1000)
 * dma-buf: name_lock fixes
 * prime: Keep object ref during mmap
 * nouveau: Fix a refcount issue; Fix device removal; Protect client
   list with dedicated mutex; Fix address CE0 address calculation
 * ttm: Fix race condition during BO eviction

Signed-off-by: Dave Airlie <[email protected]>
From: Thomas Zimmermann <[email protected]>
Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1  2 
drivers/dma-buf/dma-buf.c
drivers/gpu/drm/ttm/ttm_bo.c

index 35fe1cb5ad98dd0c781a197748fd330f4cfdcff7,92492e314bd9fa8ea12c550db255026094f2fc30..cc8f09bfa1a39c92de4981a443ee237e4896237d
@@@ -67,11 -67,14 +67,11 @@@ static void dma_buf_release(struct dent
        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_shared.active || dmabuf->cb_excl.active);
 +      BUG_ON(dmabuf->cb_in.active || dmabuf->cb_out.active);
  
        dma_buf_stats_teardown(dmabuf);
        dmabuf->ops->release(dmabuf);
@@@ -79,7 -82,6 +79,7 @@@
        if (dmabuf->resv == (struct dma_resv *)&dmabuf[1])
                dma_resv_fini(dmabuf->resv);
  
 +      WARN_ON(!list_empty(&dmabuf->attachments));
        module_put(dmabuf->owner);
        kfree(dmabuf->name);
        kfree(dmabuf);
@@@ -197,41 -199,22 +197,41 @@@ static loff_t dma_buf_llseek(struct fil
  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);
        wake_up_locked_poll(dcb->poll, dcb->active);
        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_add_cb(struct dma_resv *resv, bool write,
 +                              struct dma_buf_poll_cb_t *dcb)
 +{
 +      struct dma_resv_iter cursor;
 +      struct dma_fence *fence;
 +      int r;
 +
 +      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)
 +                      return true;
 +              dma_fence_put(fence);
 +      }
 +
 +      return false;
  }
  
  static __poll_t dma_buf_poll(struct file *file, poll_table *poll)
  {
        struct dma_buf *dmabuf;
        struct dma_resv *resv;
 -      struct dma_resv_list *fobj;
 -      struct dma_fence *fence_excl;
        __poll_t events;
 -      unsigned shared_count, seq;
  
        dmabuf = file->private_data;
        if (!dmabuf || !dmabuf->resv)
        if (!events)
                return 0;
  
 -retry:
 -      seq = read_seqcount_begin(&resv->seq);
 -      rcu_read_lock();
 +      dma_resv_lock(resv, NULL);
  
 -      fobj = rcu_dereference(resv->fence);
 -      if (fobj)
 -              shared_count = fobj->shared_count;
 -      else
 -              shared_count = 0;
 -      fence_excl = dma_resv_excl_fence(resv);
 -      if (read_seqcount_retry(&resv->seq, seq)) {
 -              rcu_read_unlock();
 -              goto retry;
 -      }
 -
 -      if (fence_excl && (!(events & EPOLLOUT) || shared_count == 0)) {
 -              struct dma_buf_poll_cb_t *dcb = &dmabuf->cb_excl;
 -              __poll_t pevents = EPOLLIN;
 -
 -              if (shared_count == 0)
 -                      pevents |= EPOLLOUT;
 +      if (events & EPOLLOUT) {
 +              struct dma_buf_poll_cb_t *dcb = &dmabuf->cb_out;
  
 +              /* Check that callback isn't busy */
                spin_lock_irq(&dmabuf->poll.lock);
 -              if (dcb->active) {
 -                      dcb->active |= pevents;
 -                      events &= ~pevents;
 -              } else
 -                      dcb->active = pevents;
 +              if (dcb->active)
 +                      events &= ~EPOLLOUT;
 +              else
 +                      dcb->active = EPOLLOUT;
                spin_unlock_irq(&dmabuf->poll.lock);
  
 -              if (events & pevents) {
 -                      if (!dma_fence_get_rcu(fence_excl)) {
 -                              /* force a recheck */
 -                              events &= ~pevents;
 -                              dma_buf_poll_cb(NULL, &dcb->cb);
 -                      } else if (!dma_fence_add_callback(fence_excl, &dcb->cb,
 -                                                         dma_buf_poll_cb)) {
 -                              events &= ~pevents;
 -                              dma_fence_put(fence_excl);
 -                      } else {
 -                              /*
 -                               * No callback queued, wake up any additional
 -                               * waiters.
 -                               */
 -                              dma_fence_put(fence_excl);
 +              if (events & EPOLLOUT) {
 +                      /* 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
 +                              events &= ~EPOLLOUT;
                }
        }
  
 -      if ((events & EPOLLOUT) && shared_count > 0) {
 -              struct dma_buf_poll_cb_t *dcb = &dmabuf->cb_shared;
 -              int i;
 +      if (events & EPOLLIN) {
 +              struct dma_buf_poll_cb_t *dcb = &dmabuf->cb_in;
  
 -              /* Only queue a new callback if no event has fired yet */
 +              /* Check that callback isn't busy */
                spin_lock_irq(&dmabuf->poll.lock);
                if (dcb->active)
 -                      events &= ~EPOLLOUT;
 +                      events &= ~EPOLLIN;
                else
 -                      dcb->active = EPOLLOUT;
 +                      dcb->active = EPOLLIN;
                spin_unlock_irq(&dmabuf->poll.lock);
  
 -              if (!(events & EPOLLOUT))
 -                      goto out;
 +              if (events & EPOLLIN) {
 +                      /* Paired with fput in dma_buf_poll_cb */
 +                      get_file(dmabuf->file);
  
 -              for (i = 0; i < shared_count; ++i) {
 -                      struct dma_fence *fence = rcu_dereference(fobj->shared[i]);
 -
 -                      if (!dma_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 &= ~EPOLLOUT;
 +                      if (!dma_buf_poll_add_cb(resv, false, dcb))
 +                              /* No callback queued, wake up any other waiters */
                                dma_buf_poll_cb(NULL, &dcb->cb);
 -                              break;
 -                      }
 -                      if (!dma_fence_add_callback(fence, &dcb->cb,
 -                                                  dma_buf_poll_cb)) {
 -                              dma_fence_put(fence);
 -                              events &= ~EPOLLOUT;
 -                              break;
 -                      }
 -                      dma_fence_put(fence);
 +                      else
 +                              events &= ~EPOLLIN;
                }
 -
 -              /* No callback queued, wake up any additional waiters. */
 -              if (i == shared_count)
 -                      dma_buf_poll_cb(NULL, &dcb->cb);
        }
  
 -out:
 -      rcu_read_unlock();
 +      dma_resv_unlock(resv);
        return events;
  }
  
@@@ -536,8 -565,8 +536,8 @@@ struct dma_buf *dma_buf_export(const st
        dmabuf->owner = exp_info->owner;
        spin_lock_init(&dmabuf->name_lock);
        init_waitqueue_head(&dmabuf->poll);
 -      dmabuf->cb_excl.poll = dmabuf->cb_shared.poll = &dmabuf->poll;
 -      dmabuf->cb_excl.active = dmabuf->cb_shared.active = 0;
 +      dmabuf->cb_in.poll = dmabuf->cb_out.poll = &dmabuf->poll;
 +      dmabuf->cb_in.active = dmabuf->cb_out.active = 0;
  
        if (!resv) {
                resv = (struct dma_resv *)&dmabuf[1];
@@@ -1338,9 -1367,10 +1338,9 @@@ static int dma_buf_debug_show(struct se
  {
        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;
  
                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,
                                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");
index 3934ee225c78d97da2c9ae848b7a62e610fe846c,1ddf458aed71cddd1e7542e78dd7b7a46a982fc1..739f11c0109cbea1972cbe92f9bfcb93f2271e0c
@@@ -69,17 -69,7 +69,17 @@@ static void ttm_bo_mem_space_debug(stru
        }
  }
  
 -static void ttm_bo_del_from_lru(struct ttm_buffer_object *bo)
 +static inline void ttm_bo_move_to_pinned(struct ttm_buffer_object *bo)
 +{
 +      struct ttm_device *bdev = bo->bdev;
 +
 +      list_move_tail(&bo->lru, &bdev->pinned);
 +
 +      if (bdev->funcs->del_from_lru_notify)
 +              bdev->funcs->del_from_lru_notify(bo);
 +}
 +
 +static inline void ttm_bo_del_from_lru(struct ttm_buffer_object *bo)
  {
        struct ttm_device *bdev = bo->bdev;
  
@@@ -108,7 -98,7 +108,7 @@@ void ttm_bo_move_to_lru_tail(struct ttm
                dma_resv_assert_held(bo->base.resv);
  
        if (bo->pin_count) {
 -              ttm_bo_del_from_lru(bo);
 +              ttm_bo_move_to_pinned(bo);
                return;
        }
  
@@@ -269,15 -259,23 +269,15 @@@ static int ttm_bo_individualize_resv(st
  static void ttm_bo_flush_all_fences(struct ttm_buffer_object *bo)
  {
        struct dma_resv *resv = &bo->base._resv;
 -      struct dma_resv_list *fobj;
 +      struct dma_resv_iter cursor;
        struct dma_fence *fence;
 -      int i;
 -
 -      rcu_read_lock();
 -      fobj = dma_resv_shared_list(resv);
 -      fence = dma_resv_excl_fence(resv);
 -      if (fence && !fence->ops->signaled)
 -              dma_fence_enable_sw_signaling(fence);
 -
 -      for (i = 0; fobj && i < fobj->shared_count; ++i) {
 -              fence = rcu_dereference(fobj->shared[i]);
  
 +      dma_resv_iter_begin(&cursor, resv, true);
 +      dma_resv_for_each_fence_unlocked(&cursor, fence) {
                if (!fence->ops->signaled)
                        dma_fence_enable_sw_signaling(fence);
        }
 -      rcu_read_unlock();
 +      dma_resv_iter_end(&cursor);
  }
  
  /**
@@@ -344,7 -342,7 +344,7 @@@ static int ttm_bo_cleanup_refs(struct t
                return ret;
        }
  
 -      ttm_bo_del_from_lru(bo);
 +      ttm_bo_move_to_pinned(bo);
        list_del_init(&bo->ddestroy);
        spin_unlock(&bo->bdev->lru_lock);
        ttm_bo_cleanup_memtype_use(bo);
@@@ -619,7 -617,8 +619,8 @@@ static bool ttm_bo_evict_swapout_allowa
                        *busy = !ret;
        }
  
-       if (ret && place && !bo->bdev->funcs->eviction_valuable(bo, place)) {
+       if (ret && place && (bo->resource->mem_type != place->mem_type ||
+               !bo->bdev->funcs->eviction_valuable(bo, place))) {
                ret = false;
                if (*locked) {
                        dma_resv_unlock(bo->base.resv);
@@@ -916,11 -915,57 +917,11 @@@ out
        return ret;
  }
  
 -static bool ttm_bo_places_compat(const struct ttm_place *places,
 -                               unsigned num_placement,
 -                               struct ttm_resource *mem,
 -                               uint32_t *new_flags)
 -{
 -      unsigned i;
 -
 -      if (mem->placement & TTM_PL_FLAG_TEMPORARY)
 -              return false;
 -
 -      for (i = 0; i < num_placement; i++) {
 -              const struct ttm_place *heap = &places[i];
 -
 -              if ((mem->start < heap->fpfn ||
 -                   (heap->lpfn != 0 && (mem->start + mem->num_pages) > heap->lpfn)))
 -                      continue;
 -
 -              *new_flags = heap->flags;
 -              if ((mem->mem_type == heap->mem_type) &&
 -                  (!(*new_flags & TTM_PL_FLAG_CONTIGUOUS) ||
 -                   (mem->placement & TTM_PL_FLAG_CONTIGUOUS)))
 -                      return true;
 -      }
 -      return false;
 -}
 -
 -bool ttm_bo_mem_compat(struct ttm_placement *placement,
 -                     struct ttm_resource *mem,
 -                     uint32_t *new_flags)
 -{
 -      if (ttm_bo_places_compat(placement->placement, placement->num_placement,
 -                               mem, new_flags))
 -              return true;
 -
 -      if ((placement->busy_placement != placement->placement ||
 -           placement->num_busy_placement > placement->num_placement) &&
 -          ttm_bo_places_compat(placement->busy_placement,
 -                               placement->num_busy_placement,
 -                               mem, new_flags))
 -              return true;
 -
 -      return false;
 -}
 -EXPORT_SYMBOL(ttm_bo_mem_compat);
 -
  int ttm_bo_validate(struct ttm_buffer_object *bo,
                    struct ttm_placement *placement,
                    struct ttm_operation_ctx *ctx)
  {
        int ret;
 -      uint32_t new_flags;
  
        dma_resv_assert_held(bo->base.resv);
  
        /*
         * Check whether we need to move buffer.
         */
 -      if (!ttm_bo_mem_compat(placement, bo->resource, &new_flags)) {
 +      if (!ttm_resource_compat(bo->resource, placement)) {
                ret = ttm_bo_move_buffer(bo, placement, ctx);
                if (ret)
                        return ret;
@@@ -1107,8 -1152,8 +1108,8 @@@ int ttm_bo_swapout(struct ttm_buffer_ob
                return -EBUSY;
  
        if (!bo->ttm || !ttm_tt_is_populated(bo->ttm) ||
 -          bo->ttm->page_flags & TTM_PAGE_FLAG_SG ||
 -          bo->ttm->page_flags & TTM_PAGE_FLAG_SWAPPED ||
 +          bo->ttm->page_flags & TTM_TT_FLAG_EXTERNAL ||
 +          bo->ttm->page_flags & TTM_TT_FLAG_SWAPPED ||
            !ttm_bo_get_unless_zero(bo)) {
                if (locked)
                        dma_resv_unlock(bo->base.resv);
                return ret == -EBUSY ? -ENOSPC : ret;
        }
  
 -      ttm_bo_del_from_lru(bo);
 +      ttm_bo_move_to_pinned(bo);
        /* TODO: Cleanup the locking */
        spin_unlock(&bo->bdev->lru_lock);
  
@@@ -1180,7 -1225,6 +1181,7 @@@ void ttm_bo_tt_destroy(struct ttm_buffe
        if (bo->ttm == NULL)
                return;
  
 +      ttm_tt_unpopulate(bo->bdev, bo->ttm);
        ttm_tt_destroy(bo->bdev, bo->ttm);
        bo->ttm = NULL;
  }
This page took 0.084621 seconds and 4 git commands to generate.