linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers
@ 2023-08-27 17:54 Dmitry Osipenko
  2023-08-27 17:54 ` [PATCH v15 01/23] drm/shmem-helper: Fix UAF in error path when freeing SGT of imported GEM Dmitry Osipenko
                   ` (23 more replies)
  0 siblings, 24 replies; 53+ messages in thread
From: Dmitry Osipenko @ 2023-08-27 17:54 UTC (permalink / raw)
  To: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Boris Brezillon, Emma Anholt, Melissa Wen, Will Deacon,
	Peter Zijlstra, Boqun Feng, Mark Rutland
  Cc: dri-devel, linux-kernel, kernel, virtualization, intel-gfx

This series:

  1. Adds common drm-shmem memory shrinker
  2. Enables shrinker for VirtIO-GPU driver
  3. Switches Panfrost driver to the common shrinker

Changelog:

v15:- Moved drm-shmem reference counters to use kref that allows to
      optimize unlocked functions, like was suggested by Boris Brezillon.

    - Changed drm/gem/shmem function names to use _locked postfix and
      dropped the _unlocked, making the naming scheme consistent across
      DRM code, like was suggested by Boris Brezillon.

    - Added patch that fixes UAF in drm-shmem for drivers that import
      dma-buf and then release buffer in the import error code path.

    - Added patch that makes drm-shmem use new flag for SGT's get_pages()
      refcounting, preventing unbalanced refcounting when GEM is freed.

    - Fixed guest blob pinning in virtio-gpu driver that was missed
      previously in the shrinker patch.

    - Moved VC4 and virtio-gpu drivers to use drm_gem_put() in
      GEM-creation error code paths, which is now required by drm-shmem
      and was missed in a previous patch versions.

    - Virtio-GPU now attaches shmem pages to host on first use and not
      when BO is created. In older patch versions there was a potential
      race condition in the BO creation code path where both
      get_sgt()+object_attach() should've been made under same resv lock,
      otherwise pages could be evicted before attachment is invoked.

    - Virtio-GPU and drm-shmem shrinker patches are split into smaller
      ones.

v14:- All the prerequisite reservation locking patches landed upstream,
      previously were a part of this series in v13 and older.

        https://lore.kernel.org/dri-devel/20230529223935.2672495-1-dmitry.osipenko@collabora.com/

    - Added patches to improve locked/unlocked function names, like was
      suggested by Boris Brezillon for v13.

    - Made all exported drm-shmem symbols GPL, like was previously
      discussed with Thomas Zimmermann on this series.

    - Improved virtio-gpu shrinker patch. Now it won't detach purged BO
      when userspace closes GEM. Crosvm (and not qemu) checks res_id on
      CMD_CTX_DETACH_RESOURCE and prints noisy error message if ID is
      invalid, which wasn't noticed before.

v13:- Updated virtio-gpu shrinker patch to use drm_gem_shmem_object_pin()
      directly instead of drm_gem_pin() and dropped patch that exported
      drm_gem_pin() functions, like was requested by Thomas Zimmermann in
      v12.

v12:- Fixed the "no previous prototype for function" warning reported by
      kernel build bot for v11.

    - Fixed the missing reservation lock reported by Intel CI for VGEM
      driver. Other drivers using drm-shmem were affected similarly to
      VGEM. The problem was in the dma-buf attachment code path that led
      to drm-shmem pinning function which assumed the held reservation lock
      by drm_gem_pin(). In the past that code path was causing trouble for
      i915 driver and we've changed the locking scheme for the attachment
      code path in the dma-buf core to let exporters to handle the locking
      themselves. After a closer investigation, I realized that my assumption
      about testing of dma-buf export code path using Panfrost driver was
      incorrect. Now I created additional local test to exrecise the Panfrost
      export path. I also reproduced the issue reported by the Intel CI for
      v10. It's all fixed now by making the drm_gem_shmem_pin() to take the
      resv lock by itself.

    - Patches are based on top of drm-tip, CC'd intel-gfx CI for testing.

v11:- Rebased on a recent linux-next. Added new patch as a result:

        drm/shmem-helper: Export drm_gem_shmem_get_pages_sgt_locked()

        It's needed by the virtio-gpu driver to swap-in/unevict shmem
        object, previously get_pages_sgt() didn't use locking.

    - Separated the "Add memory shrinker" patch into smaller parts to ease
      the reviewing, as was requested by Thomas Zimmermann:

        drm/shmem-helper: Factor out pages alloc/release from
          drm_gem_shmem_get/put_pages()
        drm/shmem-helper: Add pages_pin_count field
        drm/shmem-helper: Switch drm_gem_shmem_vmap/vunmap to use pin/unpin
        drm/shmem-helper: Factor out unpinning part from drm_gem_shmem_purge()

    - Addessed the v10 review comments from Thomas Zimmermann: return errno
      instead of bool, sort code alphabetically, rename function and etc
      minor changes.

    - Added new patch to remove the "map->is_iomem" from drm-shmem, as
      was suggested by Thomas Zimmermann.

    - Added acks and r-b's that were given to v10.

v10:- Was partially applied to misc-fixes/next.

      https://lore.kernel.org/dri-devel/6c16f303-81df-7ebe-85e9-51bb40a8b301@collabora.com/T/

Dmitry Osipenko (23):
  drm/shmem-helper: Fix UAF in error path when freeing SGT of imported
    GEM
  drm/shmem-helper: Use flag for tracking page count bumped by
    get_pages_sgt()
  drm/gem: Change locked/unlocked postfix of drm_gem_v/unmap() function
    names
  drm/gem: Add _locked postfix to functions that have unlocked
    counterpart
  drm/v3d: Replace open-coded drm_gem_shmem_free() with
    drm_gem_object_put()
  drm/virtio: Replace drm_gem_shmem_free() with drm_gem_object_put()
  drm/shmem-helper: Make all exported symbols GPL
  drm/shmem-helper: Refactor locked/unlocked functions
  drm/shmem-helper: Remove obsoleted is_iomem test
  locking/refcount, kref: Add kref_put_ww_mutex()
  dma-resv: Add kref_put_dma_resv()
  drm/shmem-helper: Add and use pages_pin_count
  drm/shmem-helper: Use kref for pages_use_count
  drm/shmem-helper: Add and use lockless drm_gem_shmem_get_pages()
  drm/shmem-helper: Switch drm_gem_shmem_vmap/vunmap to use pin/unpin
  drm/shmem-helper: Use kref for vmap_use_count
  drm/shmem-helper: Add and use drm_gem_shmem_resv_assert_held() helper
  drm/shmem-helper: Add memory shrinker
  drm/shmem-helper: Export drm_gem_shmem_get_pages_sgt_locked()
  drm/virtio: Pin display framebuffer BO
  drm/virtio: Attach shmem BOs dynamically
  drm/virtio: Support memory shrinking
  drm/panfrost: Switch to generic memory shrinker

 drivers/gpu/drm/drm_client.c                  |   6 +-
 drivers/gpu/drm/drm_gem.c                     |  26 +-
 drivers/gpu/drm/drm_gem_framebuffer_helper.c  |   6 +-
 drivers/gpu/drm/drm_gem_shmem_helper.c        | 616 +++++++++++++++---
 drivers/gpu/drm/drm_internal.h                |   4 +-
 drivers/gpu/drm/drm_prime.c                   |   4 +-
 drivers/gpu/drm/lima/lima_gem.c               |  11 +-
 drivers/gpu/drm/lima/lima_sched.c             |   4 +-
 drivers/gpu/drm/panfrost/Makefile             |   1 -
 drivers/gpu/drm/panfrost/panfrost_device.h    |   4 -
 drivers/gpu/drm/panfrost/panfrost_drv.c       |  29 +-
 drivers/gpu/drm/panfrost/panfrost_dump.c      |   4 +-
 drivers/gpu/drm/panfrost/panfrost_gem.c       |  36 +-
 drivers/gpu/drm/panfrost/panfrost_gem.h       |   9 -
 .../gpu/drm/panfrost/panfrost_gem_shrinker.c  | 122 ----
 drivers/gpu/drm/panfrost/panfrost_job.c       |  18 +-
 drivers/gpu/drm/panfrost/panfrost_mmu.c       |   4 +-
 drivers/gpu/drm/panfrost/panfrost_perfcnt.c   |   6 +-
 drivers/gpu/drm/v3d/v3d_bo.c                  |  26 +-
 drivers/gpu/drm/virtio/virtgpu_drv.h          |  22 +-
 drivers/gpu/drm/virtio/virtgpu_gem.c          |  80 +++
 drivers/gpu/drm/virtio/virtgpu_ioctl.c        |  57 +-
 drivers/gpu/drm/virtio/virtgpu_kms.c          |   8 +
 drivers/gpu/drm/virtio/virtgpu_object.c       | 147 ++++-
 drivers/gpu/drm/virtio/virtgpu_plane.c        |  17 +-
 drivers/gpu/drm/virtio/virtgpu_submit.c       |  15 +-
 drivers/gpu/drm/virtio/virtgpu_vq.c           |  40 ++
 include/drm/drm_device.h                      |  10 +-
 include/drm/drm_gem.h                         |   6 +-
 include/drm/drm_gem_shmem_helper.h            | 141 +++-
 include/linux/dma-resv.h                      |   9 +
 include/linux/kref.h                          |  12 +
 include/linux/refcount.h                      |   5 +
 include/uapi/drm/virtgpu_drm.h                |  14 +
 lib/refcount.c                                |  34 +
 35 files changed, 1167 insertions(+), 386 deletions(-)
 delete mode 100644 drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c

-- 
2.41.0


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v15 01/23] drm/shmem-helper: Fix UAF in error path when freeing SGT of imported GEM
  2023-08-27 17:54 [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Dmitry Osipenko
@ 2023-08-27 17:54 ` Dmitry Osipenko
  2023-08-28 11:16   ` Boris Brezillon
  2023-08-27 17:54 ` [PATCH v15 02/23] drm/shmem-helper: Use flag for tracking page count bumped by get_pages_sgt() Dmitry Osipenko
                   ` (22 subsequent siblings)
  23 siblings, 1 reply; 53+ messages in thread
From: Dmitry Osipenko @ 2023-08-27 17:54 UTC (permalink / raw)
  To: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Boris Brezillon, Emma Anholt, Melissa Wen, Will Deacon,
	Peter Zijlstra, Boqun Feng, Mark Rutland
  Cc: dri-devel, linux-kernel, kernel, virtualization, intel-gfx

Freeing drm-shmem GEM right after creating it using
drm_gem_shmem_prime_import_sg_table() frees SGT of the imported dma-buf
and then dma-buf frees this SGT second time.

The v3d_prime_import_sg_table() is example of a error code path where
dma-buf's SGT is freed by drm-shmem and then it's freed second time by
dma_buf_unmap_attachment() in drm_gem_prime_import_dev().

Add drm-shmem GEM flag telling that this is imported SGT shall not be
treated as own SGT, fixing the use-after-free bug.

Cc: stable@vger.kernel.org
Fixes: 2194a63a818d ("drm: Add library for shmem backed GEM objects")
Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
---
 drivers/gpu/drm/drm_gem_shmem_helper.c | 3 ++-
 include/drm/drm_gem_shmem_helper.h     | 7 +++++++
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
index a783d2245599..78d9cf2355a5 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -141,7 +141,7 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
 
 	if (obj->import_attach) {
 		drm_prime_gem_destroy(obj, shmem->sgt);
-	} else {
+	} else if (!shmem->imported_sgt) {
 		dma_resv_lock(shmem->base.resv, NULL);
 
 		drm_WARN_ON(obj->dev, shmem->vmap_use_count);
@@ -758,6 +758,7 @@ drm_gem_shmem_prime_import_sg_table(struct drm_device *dev,
 		return ERR_CAST(shmem);
 
 	shmem->sgt = sgt;
+	shmem->imported_sgt = true;
 
 	drm_dbg_prime(dev, "size = %zu\n", size);
 
diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h
index bf0c31aa8fbe..ec70a98a8fe1 100644
--- a/include/drm/drm_gem_shmem_helper.h
+++ b/include/drm/drm_gem_shmem_helper.h
@@ -73,6 +73,13 @@ struct drm_gem_shmem_object {
 	 */
 	unsigned int vmap_use_count;
 
+	/**
+	 * @imported_sgt:
+	 *
+	 * True if SG table belongs to imported dma-buf.
+	 */
+	bool imported_sgt : 1;
+
 	/**
 	 * @pages_mark_dirty_on_put:
 	 *
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v15 02/23] drm/shmem-helper: Use flag for tracking page count bumped by get_pages_sgt()
  2023-08-27 17:54 [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Dmitry Osipenko
  2023-08-27 17:54 ` [PATCH v15 01/23] drm/shmem-helper: Fix UAF in error path when freeing SGT of imported GEM Dmitry Osipenko
@ 2023-08-27 17:54 ` Dmitry Osipenko
  2023-08-28 10:55   ` Boris Brezillon
  2023-08-27 17:54 ` [PATCH v15 03/23] drm/gem: Change locked/unlocked postfix of drm_gem_v/unmap() function names Dmitry Osipenko
                   ` (21 subsequent siblings)
  23 siblings, 1 reply; 53+ messages in thread
From: Dmitry Osipenko @ 2023-08-27 17:54 UTC (permalink / raw)
  To: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Boris Brezillon, Emma Anholt, Melissa Wen, Will Deacon,
	Peter Zijlstra, Boqun Feng, Mark Rutland
  Cc: dri-devel, linux-kernel, kernel, virtualization, intel-gfx

Use separate flag for tracking page count bumped by shmem->sgt to avoid
imbalanced page counter during of drm_gem_shmem_free() time. It's fragile
to assume that populated shmem->pages at a freeing time means that the
count was bumped by drm_gem_shmem_get_pages_sgt(), using a flag removes
the ambiguity.

Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
---
 drivers/gpu/drm/drm_gem_shmem_helper.c | 3 ++-
 drivers/gpu/drm/lima/lima_gem.c        | 1 +
 include/drm/drm_gem_shmem_helper.h     | 7 +++++++
 3 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
index 78d9cf2355a5..db20b9123891 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -152,7 +152,7 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
 			sg_free_table(shmem->sgt);
 			kfree(shmem->sgt);
 		}
-		if (shmem->pages)
+		if (shmem->got_sgt)
 			drm_gem_shmem_put_pages(shmem);
 
 		drm_WARN_ON(obj->dev, shmem->pages_use_count);
@@ -687,6 +687,7 @@ static struct sg_table *drm_gem_shmem_get_pages_sgt_locked(struct drm_gem_shmem_
 	if (ret)
 		goto err_free_sgt;
 
+	shmem->got_sgt = true;
 	shmem->sgt = sgt;
 
 	return sgt;
diff --git a/drivers/gpu/drm/lima/lima_gem.c b/drivers/gpu/drm/lima/lima_gem.c
index 4f9736e5f929..28602302c281 100644
--- a/drivers/gpu/drm/lima/lima_gem.c
+++ b/drivers/gpu/drm/lima/lima_gem.c
@@ -89,6 +89,7 @@ int lima_heap_alloc(struct lima_bo *bo, struct lima_vm *vm)
 	}
 
 	*bo->base.sgt = sgt;
+	bo->base.got_sgt = true;
 
 	if (vm) {
 		ret = lima_vm_map_bo(vm, bo, old_size >> PAGE_SHIFT);
diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h
index ec70a98a8fe1..f87124629bb5 100644
--- a/include/drm/drm_gem_shmem_helper.h
+++ b/include/drm/drm_gem_shmem_helper.h
@@ -73,6 +73,13 @@ struct drm_gem_shmem_object {
 	 */
 	unsigned int vmap_use_count;
 
+	/**
+	 * @got_sgt:
+	 *
+	 * True if SG table was retrieved using drm_gem_shmem_get_pages_sgt()
+	 */
+	bool got_sgt : 1;
+
 	/**
 	 * @imported_sgt:
 	 *
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v15 03/23] drm/gem: Change locked/unlocked postfix of drm_gem_v/unmap() function names
  2023-08-27 17:54 [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Dmitry Osipenko
  2023-08-27 17:54 ` [PATCH v15 01/23] drm/shmem-helper: Fix UAF in error path when freeing SGT of imported GEM Dmitry Osipenko
  2023-08-27 17:54 ` [PATCH v15 02/23] drm/shmem-helper: Use flag for tracking page count bumped by get_pages_sgt() Dmitry Osipenko
@ 2023-08-27 17:54 ` Dmitry Osipenko
  2023-08-28 11:25   ` Boris Brezillon
  2023-08-27 17:54 ` [PATCH v15 04/23] drm/gem: Add _locked postfix to functions that have unlocked counterpart Dmitry Osipenko
                   ` (20 subsequent siblings)
  23 siblings, 1 reply; 53+ messages in thread
From: Dmitry Osipenko @ 2023-08-27 17:54 UTC (permalink / raw)
  To: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Boris Brezillon, Emma Anholt, Melissa Wen, Will Deacon,
	Peter Zijlstra, Boqun Feng, Mark Rutland
  Cc: dri-devel, linux-kernel, kernel, virtualization, intel-gfx

Make drm/gem API function names consistent by having locked function
use the _locked postfix in the name, while the unlocked variants don't
use the _unlocked postfix. Rename drm_gem_v/unmap() function names to
make them consistent with the rest of the API functions.

Suggested-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
---
 drivers/gpu/drm/drm_client.c                 |  6 +++---
 drivers/gpu/drm/drm_gem.c                    | 20 ++++++++++----------
 drivers/gpu/drm/drm_gem_framebuffer_helper.c |  6 +++---
 drivers/gpu/drm/drm_internal.h               |  4 ++--
 drivers/gpu/drm/drm_prime.c                  |  4 ++--
 drivers/gpu/drm/lima/lima_sched.c            |  4 ++--
 drivers/gpu/drm/panfrost/panfrost_dump.c     |  4 ++--
 drivers/gpu/drm/panfrost/panfrost_perfcnt.c  |  6 +++---
 include/drm/drm_gem.h                        |  4 ++--
 9 files changed, 29 insertions(+), 29 deletions(-)

diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index 037e36f2049c..29306657117a 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -265,7 +265,7 @@ void drm_client_dev_restore(struct drm_device *dev)
 static void drm_client_buffer_delete(struct drm_client_buffer *buffer)
 {
 	if (buffer->gem) {
-		drm_gem_vunmap_unlocked(buffer->gem, &buffer->map);
+		drm_gem_vunmap(buffer->gem, &buffer->map);
 		drm_gem_object_put(buffer->gem);
 	}
 
@@ -349,7 +349,7 @@ drm_client_buffer_vmap(struct drm_client_buffer *buffer,
 	 * fd_install step out of the driver backend hooks, to make that
 	 * final step optional for internal users.
 	 */
-	ret = drm_gem_vmap_unlocked(buffer->gem, map);
+	ret = drm_gem_vmap(buffer->gem, map);
 	if (ret)
 		return ret;
 
@@ -371,7 +371,7 @@ void drm_client_buffer_vunmap(struct drm_client_buffer *buffer)
 {
 	struct iosys_map *map = &buffer->map;
 
-	drm_gem_vunmap_unlocked(buffer->gem, map);
+	drm_gem_vunmap(buffer->gem, map);
 }
 EXPORT_SYMBOL(drm_client_buffer_vunmap);
 
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index 6129b89bb366..fae5832bb0bd 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -1173,7 +1173,7 @@ void drm_gem_unpin(struct drm_gem_object *obj)
 		obj->funcs->unpin(obj);
 }
 
-int drm_gem_vmap(struct drm_gem_object *obj, struct iosys_map *map)
+int drm_gem_vmap_locked(struct drm_gem_object *obj, struct iosys_map *map)
 {
 	int ret;
 
@@ -1190,9 +1190,9 @@ int drm_gem_vmap(struct drm_gem_object *obj, struct iosys_map *map)
 
 	return 0;
 }
-EXPORT_SYMBOL(drm_gem_vmap);
+EXPORT_SYMBOL(drm_gem_vmap_locked);
 
-void drm_gem_vunmap(struct drm_gem_object *obj, struct iosys_map *map)
+void drm_gem_vunmap_locked(struct drm_gem_object *obj, struct iosys_map *map)
 {
 	dma_resv_assert_held(obj->resv);
 
@@ -1205,27 +1205,27 @@ void drm_gem_vunmap(struct drm_gem_object *obj, struct iosys_map *map)
 	/* Always set the mapping to NULL. Callers may rely on this. */
 	iosys_map_clear(map);
 }
-EXPORT_SYMBOL(drm_gem_vunmap);
+EXPORT_SYMBOL(drm_gem_vunmap_locked);
 
-int drm_gem_vmap_unlocked(struct drm_gem_object *obj, struct iosys_map *map)
+int drm_gem_vmap(struct drm_gem_object *obj, struct iosys_map *map)
 {
 	int ret;
 
 	dma_resv_lock(obj->resv, NULL);
-	ret = drm_gem_vmap(obj, map);
+	ret = drm_gem_vmap_locked(obj, map);
 	dma_resv_unlock(obj->resv);
 
 	return ret;
 }
-EXPORT_SYMBOL(drm_gem_vmap_unlocked);
+EXPORT_SYMBOL(drm_gem_vmap);
 
-void drm_gem_vunmap_unlocked(struct drm_gem_object *obj, struct iosys_map *map)
+void drm_gem_vunmap(struct drm_gem_object *obj, struct iosys_map *map)
 {
 	dma_resv_lock(obj->resv, NULL);
-	drm_gem_vunmap(obj, map);
+	drm_gem_vunmap_locked(obj, map);
 	dma_resv_unlock(obj->resv);
 }
-EXPORT_SYMBOL(drm_gem_vunmap_unlocked);
+EXPORT_SYMBOL(drm_gem_vunmap);
 
 /**
  * drm_gem_lock_reservations - Sets up the ww context and acquires
diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
index 3bdb6ba37ff4..3808f47310bf 100644
--- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c
+++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
@@ -362,7 +362,7 @@ int drm_gem_fb_vmap(struct drm_framebuffer *fb, struct iosys_map *map,
 			ret = -EINVAL;
 			goto err_drm_gem_vunmap;
 		}
-		ret = drm_gem_vmap_unlocked(obj, &map[i]);
+		ret = drm_gem_vmap(obj, &map[i]);
 		if (ret)
 			goto err_drm_gem_vunmap;
 	}
@@ -384,7 +384,7 @@ int drm_gem_fb_vmap(struct drm_framebuffer *fb, struct iosys_map *map,
 		obj = drm_gem_fb_get_obj(fb, i);
 		if (!obj)
 			continue;
-		drm_gem_vunmap_unlocked(obj, &map[i]);
+		drm_gem_vunmap(obj, &map[i]);
 	}
 	return ret;
 }
@@ -411,7 +411,7 @@ void drm_gem_fb_vunmap(struct drm_framebuffer *fb, struct iosys_map *map)
 			continue;
 		if (iosys_map_is_null(&map[i]))
 			continue;
-		drm_gem_vunmap_unlocked(obj, &map[i]);
+		drm_gem_vunmap(obj, &map[i]);
 	}
 }
 EXPORT_SYMBOL(drm_gem_fb_vunmap);
diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
index ba12acd55139..243d9aa52881 100644
--- a/drivers/gpu/drm/drm_internal.h
+++ b/drivers/gpu/drm/drm_internal.h
@@ -175,8 +175,8 @@ void drm_gem_print_info(struct drm_printer *p, unsigned int indent,
 
 int drm_gem_pin(struct drm_gem_object *obj);
 void drm_gem_unpin(struct drm_gem_object *obj);
-int drm_gem_vmap(struct drm_gem_object *obj, struct iosys_map *map);
-void drm_gem_vunmap(struct drm_gem_object *obj, struct iosys_map *map);
+int drm_gem_vmap_locked(struct drm_gem_object *obj, struct iosys_map *map);
+void drm_gem_vunmap_locked(struct drm_gem_object *obj, struct iosys_map *map);
 
 /* drm_debugfs.c drm_debugfs_crc.c */
 #if defined(CONFIG_DEBUG_FS)
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index 63b709a67471..57ac5623f09a 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -682,7 +682,7 @@ int drm_gem_dmabuf_vmap(struct dma_buf *dma_buf, struct iosys_map *map)
 {
 	struct drm_gem_object *obj = dma_buf->priv;
 
-	return drm_gem_vmap(obj, map);
+	return drm_gem_vmap_locked(obj, map);
 }
 EXPORT_SYMBOL(drm_gem_dmabuf_vmap);
 
@@ -698,7 +698,7 @@ void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, struct iosys_map *map)
 {
 	struct drm_gem_object *obj = dma_buf->priv;
 
-	drm_gem_vunmap(obj, map);
+	drm_gem_vunmap_locked(obj, map);
 }
 EXPORT_SYMBOL(drm_gem_dmabuf_vunmap);
 
diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c
index ffd91a5ee299..843487128544 100644
--- a/drivers/gpu/drm/lima/lima_sched.c
+++ b/drivers/gpu/drm/lima/lima_sched.c
@@ -371,7 +371,7 @@ static void lima_sched_build_error_task_list(struct lima_sched_task *task)
 		} else {
 			buffer_chunk->size = lima_bo_size(bo);
 
-			ret = drm_gem_vmap_unlocked(&bo->base.base, &map);
+			ret = drm_gem_vmap(&bo->base.base, &map);
 			if (ret) {
 				kvfree(et);
 				goto out;
@@ -379,7 +379,7 @@ static void lima_sched_build_error_task_list(struct lima_sched_task *task)
 
 			memcpy(buffer_chunk + 1, map.vaddr, buffer_chunk->size);
 
-			drm_gem_vunmap_unlocked(&bo->base.base, &map);
+			drm_gem_vunmap(&bo->base.base, &map);
 		}
 
 		buffer_chunk = (void *)(buffer_chunk + 1) + buffer_chunk->size;
diff --git a/drivers/gpu/drm/panfrost/panfrost_dump.c b/drivers/gpu/drm/panfrost/panfrost_dump.c
index e7942ac449c6..0f30bbea9895 100644
--- a/drivers/gpu/drm/panfrost/panfrost_dump.c
+++ b/drivers/gpu/drm/panfrost/panfrost_dump.c
@@ -209,7 +209,7 @@ void panfrost_core_dump(struct panfrost_job *job)
 			goto dump_header;
 		}
 
-		ret = drm_gem_vmap_unlocked(&bo->base.base, &map);
+		ret = drm_gem_vmap(&bo->base.base, &map);
 		if (ret) {
 			dev_err(pfdev->dev, "Panfrost Dump: couldn't map Buffer Object\n");
 			iter.hdr->bomap.valid = 0;
@@ -236,7 +236,7 @@ void panfrost_core_dump(struct panfrost_job *job)
 		vaddr = map.vaddr;
 		memcpy(iter.data, vaddr, bo->base.base.size);
 
-		drm_gem_vunmap_unlocked(&bo->base.base, &map);
+		drm_gem_vunmap(&bo->base.base, &map);
 
 		iter.hdr->bomap.valid = 1;
 
diff --git a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
index ba9b6e2b2636..52befead08c6 100644
--- a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
+++ b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
@@ -106,7 +106,7 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev,
 		goto err_close_bo;
 	}
 
-	ret = drm_gem_vmap_unlocked(&bo->base, &map);
+	ret = drm_gem_vmap(&bo->base, &map);
 	if (ret)
 		goto err_put_mapping;
 	perfcnt->buf = map.vaddr;
@@ -165,7 +165,7 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev,
 	return 0;
 
 err_vunmap:
-	drm_gem_vunmap_unlocked(&bo->base, &map);
+	drm_gem_vunmap(&bo->base, &map);
 err_put_mapping:
 	panfrost_gem_mapping_put(perfcnt->mapping);
 err_close_bo:
@@ -195,7 +195,7 @@ static int panfrost_perfcnt_disable_locked(struct panfrost_device *pfdev,
 		  GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_OFF));
 
 	perfcnt->user = NULL;
-	drm_gem_vunmap_unlocked(&perfcnt->mapping->obj->base.base, &map);
+	drm_gem_vunmap(&perfcnt->mapping->obj->base.base, &map);
 	perfcnt->buf = NULL;
 	panfrost_gem_close(&perfcnt->mapping->obj->base.base, file_priv);
 	panfrost_mmu_as_put(pfdev, perfcnt->mapping->mmu);
diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
index c0b13c43b459..f338f8cfacf7 100644
--- a/include/drm/drm_gem.h
+++ b/include/drm/drm_gem.h
@@ -518,8 +518,8 @@ struct page **drm_gem_get_pages(struct drm_gem_object *obj);
 void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages,
 		bool dirty, bool accessed);
 
-int drm_gem_vmap_unlocked(struct drm_gem_object *obj, struct iosys_map *map);
-void drm_gem_vunmap_unlocked(struct drm_gem_object *obj, struct iosys_map *map);
+int drm_gem_vmap(struct drm_gem_object *obj, struct iosys_map *map);
+void drm_gem_vunmap(struct drm_gem_object *obj, struct iosys_map *map);
 
 int drm_gem_objects_lookup(struct drm_file *filp, void __user *bo_handles,
 			   int count, struct drm_gem_object ***objs_out);
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v15 04/23] drm/gem: Add _locked postfix to functions that have unlocked counterpart
  2023-08-27 17:54 [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Dmitry Osipenko
                   ` (2 preceding siblings ...)
  2023-08-27 17:54 ` [PATCH v15 03/23] drm/gem: Change locked/unlocked postfix of drm_gem_v/unmap() function names Dmitry Osipenko
@ 2023-08-27 17:54 ` Dmitry Osipenko
  2023-08-28 11:25   ` Boris Brezillon
  2023-08-27 17:54 ` [PATCH v15 05/23] drm/v3d: Replace open-coded drm_gem_shmem_free() with drm_gem_object_put() Dmitry Osipenko
                   ` (19 subsequent siblings)
  23 siblings, 1 reply; 53+ messages in thread
From: Dmitry Osipenko @ 2023-08-27 17:54 UTC (permalink / raw)
  To: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Boris Brezillon, Emma Anholt, Melissa Wen, Will Deacon,
	Peter Zijlstra, Boqun Feng, Mark Rutland
  Cc: dri-devel, linux-kernel, kernel, virtualization, intel-gfx

Add _locked postfix to drm_gem functions that have unlocked counterpart
functions to make GEM functions naming more consistent and intuitive in
regards to the locking requirements.

Suggested-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
---
 drivers/gpu/drm/drm_gem.c | 6 +++---
 include/drm/drm_gem.h     | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index fae5832bb0bd..8c0268944199 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -1488,10 +1488,10 @@ drm_gem_lru_scan(struct drm_gem_lru *lru,
 EXPORT_SYMBOL(drm_gem_lru_scan);
 
 /**
- * drm_gem_evict - helper to evict backing pages for a GEM object
+ * drm_gem_evict_locked - helper to evict backing pages for a GEM object
  * @obj: obj in question
  */
-int drm_gem_evict(struct drm_gem_object *obj)
+int drm_gem_evict_locked(struct drm_gem_object *obj)
 {
 	dma_resv_assert_held(obj->resv);
 
@@ -1503,4 +1503,4 @@ int drm_gem_evict(struct drm_gem_object *obj)
 
 	return 0;
 }
-EXPORT_SYMBOL(drm_gem_evict);
+EXPORT_SYMBOL(drm_gem_evict_locked);
diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
index f338f8cfacf7..e78e6d817451 100644
--- a/include/drm/drm_gem.h
+++ b/include/drm/drm_gem.h
@@ -542,7 +542,7 @@ unsigned long drm_gem_lru_scan(struct drm_gem_lru *lru,
 			       unsigned long *remaining,
 			       bool (*shrink)(struct drm_gem_object *obj));
 
-int drm_gem_evict(struct drm_gem_object *obj);
+int drm_gem_evict_locked(struct drm_gem_object *obj);
 
 #ifdef CONFIG_LOCKDEP
 /**
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v15 05/23] drm/v3d: Replace open-coded drm_gem_shmem_free() with drm_gem_object_put()
  2023-08-27 17:54 [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Dmitry Osipenko
                   ` (3 preceding siblings ...)
  2023-08-27 17:54 ` [PATCH v15 04/23] drm/gem: Add _locked postfix to functions that have unlocked counterpart Dmitry Osipenko
@ 2023-08-27 17:54 ` Dmitry Osipenko
  2023-08-27 17:54 ` [PATCH v15 06/23] drm/virtio: Replace " Dmitry Osipenko
                   ` (18 subsequent siblings)
  23 siblings, 0 replies; 53+ messages in thread
From: Dmitry Osipenko @ 2023-08-27 17:54 UTC (permalink / raw)
  To: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Boris Brezillon, Emma Anholt, Melissa Wen, Will Deacon,
	Peter Zijlstra, Boqun Feng, Mark Rutland
  Cc: dri-devel, linux-kernel, kernel, virtualization, intel-gfx

The drm_gem_shmem_free() doesn't put GEM's kref to zero, which becomes
important with addition of the shrinker support to drm-shmem that will
use kref=0 in order to prevent taking lock during special GEM-freeing
time in order to avoid spurious lockdep warning about locking ordering
vs fs_reclaim code paths.

Replace open-coded drm_gem_shmem_free() with drm_gem_object_put() that
drops kref to zero before freeing GEM.

Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
---
 drivers/gpu/drm/v3d/v3d_bo.c | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/v3d/v3d_bo.c b/drivers/gpu/drm/v3d/v3d_bo.c
index 8b3229a37c6d..70c1095d6eec 100644
--- a/drivers/gpu/drm/v3d/v3d_bo.c
+++ b/drivers/gpu/drm/v3d/v3d_bo.c
@@ -33,16 +33,18 @@ void v3d_free_object(struct drm_gem_object *obj)
 	struct v3d_dev *v3d = to_v3d_dev(obj->dev);
 	struct v3d_bo *bo = to_v3d_bo(obj);
 
-	v3d_mmu_remove_ptes(bo);
+	if (drm_mm_node_allocated(&bo->node)) {
+		v3d_mmu_remove_ptes(bo);
 
-	mutex_lock(&v3d->bo_lock);
-	v3d->bo_stats.num_allocated--;
-	v3d->bo_stats.pages_allocated -= obj->size >> PAGE_SHIFT;
-	mutex_unlock(&v3d->bo_lock);
+		mutex_lock(&v3d->bo_lock);
+		v3d->bo_stats.num_allocated--;
+		v3d->bo_stats.pages_allocated -= obj->size >> PAGE_SHIFT;
+		mutex_unlock(&v3d->bo_lock);
 
-	spin_lock(&v3d->mm_lock);
-	drm_mm_remove_node(&bo->node);
-	spin_unlock(&v3d->mm_lock);
+		spin_lock(&v3d->mm_lock);
+		drm_mm_remove_node(&bo->node);
+		spin_unlock(&v3d->mm_lock);
+	}
 
 	/* GPU execution may have dirtied any pages in the BO. */
 	bo->base.pages_mark_dirty_on_put = true;
@@ -142,7 +144,7 @@ struct v3d_bo *v3d_bo_create(struct drm_device *dev, struct drm_file *file_priv,
 	return bo;
 
 free_obj:
-	drm_gem_shmem_free(shmem_obj);
+	drm_gem_object_put(&shmem_obj->base);
 	return ERR_PTR(ret);
 }
 
@@ -160,7 +162,7 @@ v3d_prime_import_sg_table(struct drm_device *dev,
 
 	ret = v3d_bo_create_finish(obj);
 	if (ret) {
-		drm_gem_shmem_free(&to_v3d_bo(obj)->base);
+		drm_gem_object_put(obj);
 		return ERR_PTR(ret);
 	}
 
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v15 06/23] drm/virtio: Replace drm_gem_shmem_free() with drm_gem_object_put()
  2023-08-27 17:54 [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Dmitry Osipenko
                   ` (4 preceding siblings ...)
  2023-08-27 17:54 ` [PATCH v15 05/23] drm/v3d: Replace open-coded drm_gem_shmem_free() with drm_gem_object_put() Dmitry Osipenko
@ 2023-08-27 17:54 ` Dmitry Osipenko
  2023-08-27 17:54 ` [PATCH v15 07/23] drm/shmem-helper: Make all exported symbols GPL Dmitry Osipenko
                   ` (17 subsequent siblings)
  23 siblings, 0 replies; 53+ messages in thread
From: Dmitry Osipenko @ 2023-08-27 17:54 UTC (permalink / raw)
  To: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Boris Brezillon, Emma Anholt, Melissa Wen, Will Deacon,
	Peter Zijlstra, Boqun Feng, Mark Rutland
  Cc: dri-devel, linux-kernel, kernel, virtualization, intel-gfx

Prepare virtio_gpu_object_create() to addition of memory shrinker support
by replacing open-coded drm_gem_shmem_free() with drm_gem_object_put() that
decrements GEM refcount to 0, which becomes important for drm-shmem because
it will start to use GEM's refcount during the shmem's BO freeing time in
order to prevent spurious lockdep warning about resv lock ordering vs
fs_reclaim code paths.

Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
---
 drivers/gpu/drm/virtio/virtgpu_object.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c b/drivers/gpu/drm/virtio/virtgpu_object.c
index c7e74cf13022..343b13428125 100644
--- a/drivers/gpu/drm/virtio/virtgpu_object.c
+++ b/drivers/gpu/drm/virtio/virtgpu_object.c
@@ -244,6 +244,6 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev,
 err_put_id:
 	virtio_gpu_resource_id_put(vgdev, bo->hw_res_handle);
 err_free_gem:
-	drm_gem_shmem_free(shmem_obj);
+	drm_gem_object_put(&bo->base.base);
 	return ret;
 }
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v15 07/23] drm/shmem-helper: Make all exported symbols GPL
  2023-08-27 17:54 [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Dmitry Osipenko
                   ` (5 preceding siblings ...)
  2023-08-27 17:54 ` [PATCH v15 06/23] drm/virtio: Replace " Dmitry Osipenko
@ 2023-08-27 17:54 ` Dmitry Osipenko
  2023-08-27 17:54 ` [PATCH v15 08/23] drm/shmem-helper: Refactor locked/unlocked functions Dmitry Osipenko
                   ` (16 subsequent siblings)
  23 siblings, 0 replies; 53+ messages in thread
From: Dmitry Osipenko @ 2023-08-27 17:54 UTC (permalink / raw)
  To: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Boris Brezillon, Emma Anholt, Melissa Wen, Will Deacon,
	Peter Zijlstra, Boqun Feng, Mark Rutland
  Cc: dri-devel, linux-kernel, kernel, virtualization, intel-gfx

Make all drm-shmem exported symbols GPL to make them consistent with
the rest of drm-shmem symbols.

Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
---
 drivers/gpu/drm/drm_gem_shmem_helper.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
index db20b9123891..575704f38808 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -226,7 +226,7 @@ void drm_gem_shmem_put_pages(struct drm_gem_shmem_object *shmem)
 			  shmem->pages_mark_accessed_on_put);
 	shmem->pages = NULL;
 }
-EXPORT_SYMBOL(drm_gem_shmem_put_pages);
+EXPORT_SYMBOL_GPL(drm_gem_shmem_put_pages);
 
 static int drm_gem_shmem_pin_locked(struct drm_gem_shmem_object *shmem)
 {
@@ -271,7 +271,7 @@ int drm_gem_shmem_pin(struct drm_gem_shmem_object *shmem)
 
 	return ret;
 }
-EXPORT_SYMBOL(drm_gem_shmem_pin);
+EXPORT_SYMBOL_GPL(drm_gem_shmem_pin);
 
 /**
  * drm_gem_shmem_unpin - Unpin backing pages for a shmem GEM object
@@ -290,7 +290,7 @@ void drm_gem_shmem_unpin(struct drm_gem_shmem_object *shmem)
 	drm_gem_shmem_unpin_locked(shmem);
 	dma_resv_unlock(shmem->base.resv);
 }
-EXPORT_SYMBOL(drm_gem_shmem_unpin);
+EXPORT_SYMBOL_GPL(drm_gem_shmem_unpin);
 
 /*
  * drm_gem_shmem_vmap - Create a virtual mapping for a shmem GEM object
@@ -360,7 +360,7 @@ int drm_gem_shmem_vmap(struct drm_gem_shmem_object *shmem,
 
 	return ret;
 }
-EXPORT_SYMBOL(drm_gem_shmem_vmap);
+EXPORT_SYMBOL_GPL(drm_gem_shmem_vmap);
 
 /*
  * drm_gem_shmem_vunmap - Unmap a virtual mapping for a shmem GEM object
@@ -396,7 +396,7 @@ void drm_gem_shmem_vunmap(struct drm_gem_shmem_object *shmem,
 
 	shmem->vaddr = NULL;
 }
-EXPORT_SYMBOL(drm_gem_shmem_vunmap);
+EXPORT_SYMBOL_GPL(drm_gem_shmem_vunmap);
 
 static int
 drm_gem_shmem_create_with_handle(struct drm_file *file_priv,
@@ -435,7 +435,7 @@ int drm_gem_shmem_madvise(struct drm_gem_shmem_object *shmem, int madv)
 
 	return (madv >= 0);
 }
-EXPORT_SYMBOL(drm_gem_shmem_madvise);
+EXPORT_SYMBOL_GPL(drm_gem_shmem_madvise);
 
 void drm_gem_shmem_purge(struct drm_gem_shmem_object *shmem)
 {
@@ -467,7 +467,7 @@ void drm_gem_shmem_purge(struct drm_gem_shmem_object *shmem)
 
 	invalidate_mapping_pages(file_inode(obj->filp)->i_mapping, 0, (loff_t)-1);
 }
-EXPORT_SYMBOL(drm_gem_shmem_purge);
+EXPORT_SYMBOL_GPL(drm_gem_shmem_purge);
 
 /**
  * drm_gem_shmem_dumb_create - Create a dumb shmem buffer object
@@ -636,7 +636,7 @@ void drm_gem_shmem_print_info(const struct drm_gem_shmem_object *shmem,
 	drm_printf_indent(p, indent, "vmap_use_count=%u\n", shmem->vmap_use_count);
 	drm_printf_indent(p, indent, "vaddr=%p\n", shmem->vaddr);
 }
-EXPORT_SYMBOL(drm_gem_shmem_print_info);
+EXPORT_SYMBOL_GPL(drm_gem_shmem_print_info);
 
 /**
  * drm_gem_shmem_get_sg_table - Provide a scatter/gather table of pinned
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v15 08/23] drm/shmem-helper: Refactor locked/unlocked functions
  2023-08-27 17:54 [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Dmitry Osipenko
                   ` (6 preceding siblings ...)
  2023-08-27 17:54 ` [PATCH v15 07/23] drm/shmem-helper: Make all exported symbols GPL Dmitry Osipenko
@ 2023-08-27 17:54 ` Dmitry Osipenko
  2023-08-28 11:28   ` Boris Brezillon
  2023-08-27 17:54 ` [PATCH v15 09/23] drm/shmem-helper: Remove obsoleted is_iomem test Dmitry Osipenko
                   ` (15 subsequent siblings)
  23 siblings, 1 reply; 53+ messages in thread
From: Dmitry Osipenko @ 2023-08-27 17:54 UTC (permalink / raw)
  To: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Boris Brezillon, Emma Anholt, Melissa Wen, Will Deacon,
	Peter Zijlstra, Boqun Feng, Mark Rutland
  Cc: dri-devel, linux-kernel, kernel, virtualization, intel-gfx

Add locked and remove unlocked postfixes from drm-shmem function names,
making names consistent with the drm/gem core code.

Suggested-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
---
 drivers/gpu/drm/drm_gem_shmem_helper.c        | 64 +++++++++----------
 drivers/gpu/drm/lima/lima_gem.c               |  8 +--
 drivers/gpu/drm/panfrost/panfrost_drv.c       |  2 +-
 drivers/gpu/drm/panfrost/panfrost_gem.c       |  6 +-
 .../gpu/drm/panfrost/panfrost_gem_shrinker.c  |  2 +-
 drivers/gpu/drm/panfrost/panfrost_mmu.c       |  2 +-
 drivers/gpu/drm/v3d/v3d_bo.c                  |  4 +-
 drivers/gpu/drm/virtio/virtgpu_object.c       |  4 +-
 include/drm/drm_gem_shmem_helper.h            | 36 +++++------
 9 files changed, 64 insertions(+), 64 deletions(-)

diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
index 575704f38808..f053dc511508 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -43,8 +43,8 @@ static const struct drm_gem_object_funcs drm_gem_shmem_funcs = {
 	.pin = drm_gem_shmem_object_pin,
 	.unpin = drm_gem_shmem_object_unpin,
 	.get_sg_table = drm_gem_shmem_object_get_sg_table,
-	.vmap = drm_gem_shmem_object_vmap,
-	.vunmap = drm_gem_shmem_object_vunmap,
+	.vmap = drm_gem_shmem_object_vmap_locked,
+	.vunmap = drm_gem_shmem_object_vunmap_locked,
 	.mmap = drm_gem_shmem_object_mmap,
 	.vm_ops = &drm_gem_shmem_vm_ops,
 };
@@ -153,7 +153,7 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
 			kfree(shmem->sgt);
 		}
 		if (shmem->got_sgt)
-			drm_gem_shmem_put_pages(shmem);
+			drm_gem_shmem_put_pages_locked(shmem);
 
 		drm_WARN_ON(obj->dev, shmem->pages_use_count);
 
@@ -165,7 +165,7 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
 }
 EXPORT_SYMBOL_GPL(drm_gem_shmem_free);
 
-static int drm_gem_shmem_get_pages(struct drm_gem_shmem_object *shmem)
+static int drm_gem_shmem_get_pages_locked(struct drm_gem_shmem_object *shmem)
 {
 	struct drm_gem_object *obj = &shmem->base;
 	struct page **pages;
@@ -199,12 +199,12 @@ static int drm_gem_shmem_get_pages(struct drm_gem_shmem_object *shmem)
 }
 
 /*
- * drm_gem_shmem_put_pages - Decrease use count on the backing pages for a shmem GEM object
+ * drm_gem_shmem_put_pages_locked - Decrease use count on the backing pages for a shmem GEM object
  * @shmem: shmem GEM object
  *
  * This function decreases the use count and puts the backing pages when use drops to zero.
  */
-void drm_gem_shmem_put_pages(struct drm_gem_shmem_object *shmem)
+void drm_gem_shmem_put_pages_locked(struct drm_gem_shmem_object *shmem)
 {
 	struct drm_gem_object *obj = &shmem->base;
 
@@ -226,7 +226,7 @@ void drm_gem_shmem_put_pages(struct drm_gem_shmem_object *shmem)
 			  shmem->pages_mark_accessed_on_put);
 	shmem->pages = NULL;
 }
-EXPORT_SYMBOL_GPL(drm_gem_shmem_put_pages);
+EXPORT_SYMBOL_GPL(drm_gem_shmem_put_pages_locked);
 
 static int drm_gem_shmem_pin_locked(struct drm_gem_shmem_object *shmem)
 {
@@ -234,7 +234,7 @@ static int drm_gem_shmem_pin_locked(struct drm_gem_shmem_object *shmem)
 
 	dma_resv_assert_held(shmem->base.resv);
 
-	ret = drm_gem_shmem_get_pages(shmem);
+	ret = drm_gem_shmem_get_pages_locked(shmem);
 
 	return ret;
 }
@@ -243,7 +243,7 @@ static void drm_gem_shmem_unpin_locked(struct drm_gem_shmem_object *shmem)
 {
 	dma_resv_assert_held(shmem->base.resv);
 
-	drm_gem_shmem_put_pages(shmem);
+	drm_gem_shmem_put_pages_locked(shmem);
 }
 
 /**
@@ -293,7 +293,7 @@ void drm_gem_shmem_unpin(struct drm_gem_shmem_object *shmem)
 EXPORT_SYMBOL_GPL(drm_gem_shmem_unpin);
 
 /*
- * drm_gem_shmem_vmap - Create a virtual mapping for a shmem GEM object
+ * drm_gem_shmem_vmap_locked - Create a virtual mapping for a shmem GEM object
  * @shmem: shmem GEM object
  * @map: Returns the kernel virtual address of the SHMEM GEM object's backing
  *       store.
@@ -302,13 +302,13 @@ EXPORT_SYMBOL_GPL(drm_gem_shmem_unpin);
  * exists for the buffer backing the shmem GEM object. It hides the differences
  * between dma-buf imported and natively allocated objects.
  *
- * Acquired mappings should be cleaned up by calling drm_gem_shmem_vunmap().
+ * Acquired mappings should be cleaned up by calling drm_gem_shmem_vunmap_locked().
  *
  * Returns:
  * 0 on success or a negative error code on failure.
  */
-int drm_gem_shmem_vmap(struct drm_gem_shmem_object *shmem,
-		       struct iosys_map *map)
+int drm_gem_shmem_vmap_locked(struct drm_gem_shmem_object *shmem,
+			      struct iosys_map *map)
 {
 	struct drm_gem_object *obj = &shmem->base;
 	int ret = 0;
@@ -331,7 +331,7 @@ int drm_gem_shmem_vmap(struct drm_gem_shmem_object *shmem,
 			return 0;
 		}
 
-		ret = drm_gem_shmem_get_pages(shmem);
+		ret = drm_gem_shmem_get_pages_locked(shmem);
 		if (ret)
 			goto err_zero_use;
 
@@ -354,28 +354,28 @@ int drm_gem_shmem_vmap(struct drm_gem_shmem_object *shmem,
 
 err_put_pages:
 	if (!obj->import_attach)
-		drm_gem_shmem_put_pages(shmem);
+		drm_gem_shmem_put_pages_locked(shmem);
 err_zero_use:
 	shmem->vmap_use_count = 0;
 
 	return ret;
 }
-EXPORT_SYMBOL_GPL(drm_gem_shmem_vmap);
+EXPORT_SYMBOL_GPL(drm_gem_shmem_vmap_locked);
 
 /*
- * drm_gem_shmem_vunmap - Unmap a virtual mapping for a shmem GEM object
+ * drm_gem_shmem_vunmap_locked - Unmap a virtual mapping for a shmem GEM object
  * @shmem: shmem GEM object
  * @map: Kernel virtual address where the SHMEM GEM object was mapped
  *
  * This function cleans up a kernel virtual address mapping acquired by
- * drm_gem_shmem_vmap(). The mapping is only removed when the use count drops to
- * zero.
+ * drm_gem_shmem_vmap_locked(). The mapping is only removed when the use count
+ * drops to zero.
  *
  * This function hides the differences between dma-buf imported and natively
  * allocated objects.
  */
-void drm_gem_shmem_vunmap(struct drm_gem_shmem_object *shmem,
-			  struct iosys_map *map)
+void drm_gem_shmem_vunmap_locked(struct drm_gem_shmem_object *shmem,
+				 struct iosys_map *map)
 {
 	struct drm_gem_object *obj = &shmem->base;
 
@@ -391,12 +391,12 @@ void drm_gem_shmem_vunmap(struct drm_gem_shmem_object *shmem,
 			return;
 
 		vunmap(shmem->vaddr);
-		drm_gem_shmem_put_pages(shmem);
+		drm_gem_shmem_put_pages_locked(shmem);
 	}
 
 	shmem->vaddr = NULL;
 }
-EXPORT_SYMBOL_GPL(drm_gem_shmem_vunmap);
+EXPORT_SYMBOL_GPL(drm_gem_shmem_vunmap_locked);
 
 static int
 drm_gem_shmem_create_with_handle(struct drm_file *file_priv,
@@ -424,7 +424,7 @@ drm_gem_shmem_create_with_handle(struct drm_file *file_priv,
 /* Update madvise status, returns true if not purged, else
  * false or -errno.
  */
-int drm_gem_shmem_madvise(struct drm_gem_shmem_object *shmem, int madv)
+int drm_gem_shmem_madvise_locked(struct drm_gem_shmem_object *shmem, int madv)
 {
 	dma_resv_assert_held(shmem->base.resv);
 
@@ -435,9 +435,9 @@ int drm_gem_shmem_madvise(struct drm_gem_shmem_object *shmem, int madv)
 
 	return (madv >= 0);
 }
-EXPORT_SYMBOL_GPL(drm_gem_shmem_madvise);
+EXPORT_SYMBOL_GPL(drm_gem_shmem_madvise_locked);
 
-void drm_gem_shmem_purge(struct drm_gem_shmem_object *shmem)
+void drm_gem_shmem_purge_locked(struct drm_gem_shmem_object *shmem)
 {
 	struct drm_gem_object *obj = &shmem->base;
 	struct drm_device *dev = obj->dev;
@@ -451,7 +451,7 @@ void drm_gem_shmem_purge(struct drm_gem_shmem_object *shmem)
 	kfree(shmem->sgt);
 	shmem->sgt = NULL;
 
-	drm_gem_shmem_put_pages(shmem);
+	drm_gem_shmem_put_pages_locked(shmem);
 
 	shmem->madv = -1;
 
@@ -467,7 +467,7 @@ void drm_gem_shmem_purge(struct drm_gem_shmem_object *shmem)
 
 	invalidate_mapping_pages(file_inode(obj->filp)->i_mapping, 0, (loff_t)-1);
 }
-EXPORT_SYMBOL_GPL(drm_gem_shmem_purge);
+EXPORT_SYMBOL_GPL(drm_gem_shmem_purge_locked);
 
 /**
  * drm_gem_shmem_dumb_create - Create a dumb shmem buffer object
@@ -564,7 +564,7 @@ static void drm_gem_shmem_vm_close(struct vm_area_struct *vma)
 	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
 
 	dma_resv_lock(shmem->base.resv, NULL);
-	drm_gem_shmem_put_pages(shmem);
+	drm_gem_shmem_put_pages_locked(shmem);
 	dma_resv_unlock(shmem->base.resv);
 
 	drm_gem_vm_close(vma);
@@ -605,7 +605,7 @@ int drm_gem_shmem_mmap(struct drm_gem_shmem_object *shmem, struct vm_area_struct
 	}
 
 	dma_resv_lock(shmem->base.resv, NULL);
-	ret = drm_gem_shmem_get_pages(shmem);
+	ret = drm_gem_shmem_get_pages_locked(shmem);
 	dma_resv_unlock(shmem->base.resv);
 
 	if (ret)
@@ -673,7 +673,7 @@ static struct sg_table *drm_gem_shmem_get_pages_sgt_locked(struct drm_gem_shmem_
 
 	drm_WARN_ON(obj->dev, obj->import_attach);
 
-	ret = drm_gem_shmem_get_pages(shmem);
+	ret = drm_gem_shmem_get_pages_locked(shmem);
 	if (ret)
 		return ERR_PTR(ret);
 
@@ -696,7 +696,7 @@ static struct sg_table *drm_gem_shmem_get_pages_sgt_locked(struct drm_gem_shmem_
 	sg_free_table(sgt);
 	kfree(sgt);
 err_put_pages:
-	drm_gem_shmem_put_pages(shmem);
+	drm_gem_shmem_put_pages_locked(shmem);
 	return ERR_PTR(ret);
 }
 
diff --git a/drivers/gpu/drm/lima/lima_gem.c b/drivers/gpu/drm/lima/lima_gem.c
index 28602302c281..7d74c71f5558 100644
--- a/drivers/gpu/drm/lima/lima_gem.c
+++ b/drivers/gpu/drm/lima/lima_gem.c
@@ -181,7 +181,7 @@ static int lima_gem_pin(struct drm_gem_object *obj)
 	if (bo->heap_size)
 		return -EINVAL;
 
-	return drm_gem_shmem_pin(&bo->base);
+	return drm_gem_shmem_object_pin(obj);
 }
 
 static int lima_gem_vmap(struct drm_gem_object *obj, struct iosys_map *map)
@@ -191,7 +191,7 @@ static int lima_gem_vmap(struct drm_gem_object *obj, struct iosys_map *map)
 	if (bo->heap_size)
 		return -EINVAL;
 
-	return drm_gem_shmem_vmap(&bo->base, map);
+	return drm_gem_shmem_object_vmap_locked(obj, map);
 }
 
 static int lima_gem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
@@ -201,7 +201,7 @@ static int lima_gem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
 	if (bo->heap_size)
 		return -EINVAL;
 
-	return drm_gem_shmem_mmap(&bo->base, vma);
+	return drm_gem_shmem_object_mmap(obj, vma);
 }
 
 static const struct drm_gem_object_funcs lima_gem_funcs = {
@@ -213,7 +213,7 @@ static const struct drm_gem_object_funcs lima_gem_funcs = {
 	.unpin = drm_gem_shmem_object_unpin,
 	.get_sg_table = drm_gem_shmem_object_get_sg_table,
 	.vmap = lima_gem_vmap,
-	.vunmap = drm_gem_shmem_object_vunmap,
+	.vunmap = drm_gem_shmem_object_vunmap_locked,
 	.mmap = lima_gem_mmap,
 	.vm_ops = &drm_gem_shmem_vm_ops,
 };
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c
index a2ab99698ca8..175443eacead 100644
--- a/drivers/gpu/drm/panfrost/panfrost_drv.c
+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
@@ -436,7 +436,7 @@ static int panfrost_ioctl_madvise(struct drm_device *dev, void *data,
 		}
 	}
 
-	args->retained = drm_gem_shmem_madvise(&bo->base, args->madv);
+	args->retained = drm_gem_shmem_madvise_locked(&bo->base, args->madv);
 
 	if (args->retained) {
 		if (args->madv == PANFROST_MADV_DONTNEED)
diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.c b/drivers/gpu/drm/panfrost/panfrost_gem.c
index 3c812fbd126f..59c8c73c6a59 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gem.c
+++ b/drivers/gpu/drm/panfrost/panfrost_gem.c
@@ -192,7 +192,7 @@ static int panfrost_gem_pin(struct drm_gem_object *obj)
 	if (bo->is_heap)
 		return -EINVAL;
 
-	return drm_gem_shmem_pin(&bo->base);
+	return drm_gem_shmem_object_pin(obj);
 }
 
 static const struct drm_gem_object_funcs panfrost_gem_funcs = {
@@ -203,8 +203,8 @@ static const struct drm_gem_object_funcs panfrost_gem_funcs = {
 	.pin = panfrost_gem_pin,
 	.unpin = drm_gem_shmem_object_unpin,
 	.get_sg_table = drm_gem_shmem_object_get_sg_table,
-	.vmap = drm_gem_shmem_object_vmap,
-	.vunmap = drm_gem_shmem_object_vunmap,
+	.vmap = drm_gem_shmem_object_vmap_locked,
+	.vunmap = drm_gem_shmem_object_vunmap_locked,
 	.mmap = drm_gem_shmem_object_mmap,
 	.vm_ops = &drm_gem_shmem_vm_ops,
 };
diff --git a/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c b/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
index 6a71a2555f85..72193bd734e1 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
+++ b/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
@@ -52,7 +52,7 @@ static bool panfrost_gem_purge(struct drm_gem_object *obj)
 		goto unlock_mappings;
 
 	panfrost_gem_teardown_mappings_locked(bo);
-	drm_gem_shmem_purge(&bo->base);
+	drm_gem_shmem_purge_locked(&bo->base);
 	ret = true;
 
 	dma_resv_unlock(shmem->base.resv);
diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c
index c0123d09f699..7771769f0ce0 100644
--- a/drivers/gpu/drm/panfrost/panfrost_mmu.c
+++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c
@@ -535,7 +535,7 @@ static int panfrost_mmu_map_fault_addr(struct panfrost_device *pfdev, int as,
 err_map:
 	sg_free_table(sgt);
 err_pages:
-	drm_gem_shmem_put_pages(&bo->base);
+	drm_gem_shmem_put_pages_locked(&bo->base);
 err_unlock:
 	dma_resv_unlock(obj->resv);
 err_bo:
diff --git a/drivers/gpu/drm/v3d/v3d_bo.c b/drivers/gpu/drm/v3d/v3d_bo.c
index 70c1095d6eec..6a0e7b6177d5 100644
--- a/drivers/gpu/drm/v3d/v3d_bo.c
+++ b/drivers/gpu/drm/v3d/v3d_bo.c
@@ -58,8 +58,8 @@ static const struct drm_gem_object_funcs v3d_gem_funcs = {
 	.pin = drm_gem_shmem_object_pin,
 	.unpin = drm_gem_shmem_object_unpin,
 	.get_sg_table = drm_gem_shmem_object_get_sg_table,
-	.vmap = drm_gem_shmem_object_vmap,
-	.vunmap = drm_gem_shmem_object_vunmap,
+	.vmap = drm_gem_shmem_object_vmap_locked,
+	.vunmap = drm_gem_shmem_object_vunmap_locked,
 	.mmap = drm_gem_shmem_object_mmap,
 	.vm_ops = &drm_gem_shmem_vm_ops,
 };
diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c b/drivers/gpu/drm/virtio/virtgpu_object.c
index 343b13428125..97020ed56b81 100644
--- a/drivers/gpu/drm/virtio/virtgpu_object.c
+++ b/drivers/gpu/drm/virtio/virtgpu_object.c
@@ -106,8 +106,8 @@ static const struct drm_gem_object_funcs virtio_gpu_shmem_funcs = {
 	.pin = drm_gem_shmem_object_pin,
 	.unpin = drm_gem_shmem_object_unpin,
 	.get_sg_table = drm_gem_shmem_object_get_sg_table,
-	.vmap = drm_gem_shmem_object_vmap,
-	.vunmap = drm_gem_shmem_object_vunmap,
+	.vmap = drm_gem_shmem_object_vmap_locked,
+	.vunmap = drm_gem_shmem_object_vunmap_locked,
 	.mmap = drm_gem_shmem_object_mmap,
 	.vm_ops = &drm_gem_shmem_vm_ops,
 };
diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h
index f87124629bb5..ec2d8b24e3cf 100644
--- a/include/drm/drm_gem_shmem_helper.h
+++ b/include/drm/drm_gem_shmem_helper.h
@@ -113,16 +113,16 @@ struct drm_gem_shmem_object {
 struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size);
 void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem);
 
-void drm_gem_shmem_put_pages(struct drm_gem_shmem_object *shmem);
+void drm_gem_shmem_put_pages_locked(struct drm_gem_shmem_object *shmem);
 int drm_gem_shmem_pin(struct drm_gem_shmem_object *shmem);
 void drm_gem_shmem_unpin(struct drm_gem_shmem_object *shmem);
-int drm_gem_shmem_vmap(struct drm_gem_shmem_object *shmem,
-		       struct iosys_map *map);
-void drm_gem_shmem_vunmap(struct drm_gem_shmem_object *shmem,
-			  struct iosys_map *map);
+int drm_gem_shmem_vmap_locked(struct drm_gem_shmem_object *shmem,
+			      struct iosys_map *map);
+void drm_gem_shmem_vunmap_locked(struct drm_gem_shmem_object *shmem,
+				 struct iosys_map *map);
 int drm_gem_shmem_mmap(struct drm_gem_shmem_object *shmem, struct vm_area_struct *vma);
 
-int drm_gem_shmem_madvise(struct drm_gem_shmem_object *shmem, int madv);
+int drm_gem_shmem_madvise_locked(struct drm_gem_shmem_object *shmem, int madv);
 
 static inline bool drm_gem_shmem_is_purgeable(struct drm_gem_shmem_object *shmem)
 {
@@ -131,7 +131,7 @@ static inline bool drm_gem_shmem_is_purgeable(struct drm_gem_shmem_object *shmem
 		!shmem->base.dma_buf && !shmem->base.import_attach;
 }
 
-void drm_gem_shmem_purge(struct drm_gem_shmem_object *shmem);
+void drm_gem_shmem_purge_locked(struct drm_gem_shmem_object *shmem);
 
 struct sg_table *drm_gem_shmem_get_sg_table(struct drm_gem_shmem_object *shmem);
 struct sg_table *drm_gem_shmem_get_pages_sgt(struct drm_gem_shmem_object *shmem);
@@ -222,22 +222,22 @@ static inline struct sg_table *drm_gem_shmem_object_get_sg_table(struct drm_gem_
 }
 
 /*
- * drm_gem_shmem_object_vmap - GEM object function for drm_gem_shmem_vmap()
+ * drm_gem_shmem_object_vmap_locked - GEM object function for drm_gem_shmem_vmap_locked()
  * @obj: GEM object
  * @map: Returns the kernel virtual address of the SHMEM GEM object's backing store.
  *
- * This function wraps drm_gem_shmem_vmap(). Drivers that employ the shmem helpers should
- * use it as their &drm_gem_object_funcs.vmap handler.
+ * This function wraps drm_gem_shmem_vmap_locked(). Drivers that employ the shmem
+ * helpers should use it as their &drm_gem_object_funcs.vmap handler.
  *
  * Returns:
  * 0 on success or a negative error code on failure.
  */
-static inline int drm_gem_shmem_object_vmap(struct drm_gem_object *obj,
-					    struct iosys_map *map)
+static inline int drm_gem_shmem_object_vmap_locked(struct drm_gem_object *obj,
+						   struct iosys_map *map)
 {
 	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
 
-	return drm_gem_shmem_vmap(shmem, map);
+	return drm_gem_shmem_vmap_locked(shmem, map);
 }
 
 /*
@@ -245,15 +245,15 @@ static inline int drm_gem_shmem_object_vmap(struct drm_gem_object *obj,
  * @obj: GEM object
  * @map: Kernel virtual address where the SHMEM GEM object was mapped
  *
- * This function wraps drm_gem_shmem_vunmap(). Drivers that employ the shmem helpers should
- * use it as their &drm_gem_object_funcs.vunmap handler.
+ * This function wraps drm_gem_shmem_vunmap_locked(). Drivers that employ the shmem
+ * helpers should use it as their &drm_gem_object_funcs.vunmap handler.
  */
-static inline void drm_gem_shmem_object_vunmap(struct drm_gem_object *obj,
-					       struct iosys_map *map)
+static inline void drm_gem_shmem_object_vunmap_locked(struct drm_gem_object *obj,
+						      struct iosys_map *map)
 {
 	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
 
-	drm_gem_shmem_vunmap(shmem, map);
+	drm_gem_shmem_vunmap_locked(shmem, map);
 }
 
 /**
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v15 09/23] drm/shmem-helper: Remove obsoleted is_iomem test
  2023-08-27 17:54 [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Dmitry Osipenko
                   ` (7 preceding siblings ...)
  2023-08-27 17:54 ` [PATCH v15 08/23] drm/shmem-helper: Refactor locked/unlocked functions Dmitry Osipenko
@ 2023-08-27 17:54 ` Dmitry Osipenko
  2023-08-28 11:29   ` Boris Brezillon
  2023-08-27 17:54 ` [PATCH v15 10/23] locking/refcount, kref: Add kref_put_ww_mutex() Dmitry Osipenko
                   ` (14 subsequent siblings)
  23 siblings, 1 reply; 53+ messages in thread
From: Dmitry Osipenko @ 2023-08-27 17:54 UTC (permalink / raw)
  To: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Boris Brezillon, Emma Anholt, Melissa Wen, Will Deacon,
	Peter Zijlstra, Boqun Feng, Mark Rutland
  Cc: dri-devel, linux-kernel, kernel, virtualization, intel-gfx

Everything that uses the mapped buffer should by agnostic to is_iomem.
The only reason for the is_iomem test is that we're setting shmem->vaddr
to the returned map->vaddr. Now that the shmem->vaddr code is gone, remove
the obsoleted is_iomem test to clean up the code.

Suggested-by: Thomas Zimmermann <tzimmermann@suse.de>
Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
---
 drivers/gpu/drm/drm_gem_shmem_helper.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
index f053dc511508..d545d3d227d7 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -315,12 +315,6 @@ int drm_gem_shmem_vmap_locked(struct drm_gem_shmem_object *shmem,
 
 	if (obj->import_attach) {
 		ret = dma_buf_vmap(obj->import_attach->dmabuf, map);
-		if (!ret) {
-			if (drm_WARN_ON(obj->dev, map->is_iomem)) {
-				dma_buf_vunmap(obj->import_attach->dmabuf, map);
-				return -EIO;
-			}
-		}
 	} else {
 		pgprot_t prot = PAGE_KERNEL;
 
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v15 10/23] locking/refcount, kref: Add kref_put_ww_mutex()
  2023-08-27 17:54 [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Dmitry Osipenko
                   ` (8 preceding siblings ...)
  2023-08-27 17:54 ` [PATCH v15 09/23] drm/shmem-helper: Remove obsoleted is_iomem test Dmitry Osipenko
@ 2023-08-27 17:54 ` Dmitry Osipenko
  2023-08-28  9:26   ` Boris Brezillon
  2023-08-27 17:54 ` [PATCH v15 11/23] dma-resv: Add kref_put_dma_resv() Dmitry Osipenko
                   ` (13 subsequent siblings)
  23 siblings, 1 reply; 53+ messages in thread
From: Dmitry Osipenko @ 2023-08-27 17:54 UTC (permalink / raw)
  To: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Boris Brezillon, Emma Anholt, Melissa Wen, Will Deacon,
	Peter Zijlstra, Boqun Feng, Mark Rutland
  Cc: dri-devel, linux-kernel, kernel, virtualization, intel-gfx

Introduce kref_put_ww_mutex() helper that will handle the wait-wound
mutex auto-locking on kref_put(). This helper is wanted by DRM drivers
that extensively use dma-reservation locking which in turns uses ww-mutex.

Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
---
 include/linux/kref.h     | 12 ++++++++++++
 include/linux/refcount.h |  5 +++++
 lib/refcount.c           | 34 ++++++++++++++++++++++++++++++++++
 3 files changed, 51 insertions(+)

diff --git a/include/linux/kref.h b/include/linux/kref.h
index d32e21a2538c..b2d8dc6e9ae0 100644
--- a/include/linux/kref.h
+++ b/include/linux/kref.h
@@ -90,6 +90,18 @@ static inline int kref_put_lock(struct kref *kref,
 	return 0;
 }
 
+static inline int kref_put_ww_mutex(struct kref *kref,
+				    void (*release)(struct kref *kref),
+				    struct ww_mutex *lock,
+				    struct ww_acquire_ctx *ctx)
+{
+	if (refcount_dec_and_ww_mutex_lock(&kref->refcount, lock, ctx)) {
+		release(kref);
+		return 1;
+	}
+	return 0;
+}
+
 /**
  * kref_get_unless_zero - Increment refcount for object unless it is zero.
  * @kref: object.
diff --git a/include/linux/refcount.h b/include/linux/refcount.h
index a62fcca97486..be9ad272bc77 100644
--- a/include/linux/refcount.h
+++ b/include/linux/refcount.h
@@ -99,6 +99,8 @@
 #include <linux/spinlock_types.h>
 
 struct mutex;
+struct ww_mutex;
+struct ww_acquire_ctx;
 
 /**
  * typedef refcount_t - variant of atomic_t specialized for reference counts
@@ -366,4 +368,7 @@ extern __must_check bool refcount_dec_and_lock(refcount_t *r, spinlock_t *lock)
 extern __must_check bool refcount_dec_and_lock_irqsave(refcount_t *r,
 						       spinlock_t *lock,
 						       unsigned long *flags) __cond_acquires(lock);
+extern __must_check bool refcount_dec_and_ww_mutex_lock(refcount_t *r,
+							struct ww_mutex *lock,
+							struct ww_acquire_ctx *ctx) __cond_acquires(&lock->base);
 #endif /* _LINUX_REFCOUNT_H */
diff --git a/lib/refcount.c b/lib/refcount.c
index a207a8f22b3c..3f6fd0ceed02 100644
--- a/lib/refcount.c
+++ b/lib/refcount.c
@@ -6,6 +6,7 @@
 #include <linux/mutex.h>
 #include <linux/refcount.h>
 #include <linux/spinlock.h>
+#include <linux/ww_mutex.h>
 #include <linux/bug.h>
 
 #define REFCOUNT_WARN(str)	WARN_ONCE(1, "refcount_t: " str ".\n")
@@ -184,3 +185,36 @@ bool refcount_dec_and_lock_irqsave(refcount_t *r, spinlock_t *lock,
 	return true;
 }
 EXPORT_SYMBOL(refcount_dec_and_lock_irqsave);
+
+/**
+ * refcount_dec_and_ww_mutex_lock - return holding ww-mutex if able to
+ *                                  decrement refcount to 0
+ * @r: the refcount
+ * @lock: the ww-mutex to be locked
+ * @ctx: wait-wound context
+ *
+ * Similar to atomic_dec_and_lock(), it will WARN on underflow and fail to
+ * decrement when saturated at REFCOUNT_SATURATED.
+ *
+ * Provides release memory ordering, such that prior loads and stores are done
+ * before, and provides a control dependency such that free() must come after.
+ * See the comment on top.
+ *
+ * Return: true and hold ww-mutex lock if able to decrement refcount to 0,
+ *         false otherwise
+ */
+bool refcount_dec_and_ww_mutex_lock(refcount_t *r, struct ww_mutex *lock,
+				    struct ww_acquire_ctx *ctx)
+{
+	if (refcount_dec_not_one(r))
+		return false;
+
+	ww_mutex_lock(lock, ctx);
+	if (!refcount_dec_and_test(r)) {
+		ww_mutex_unlock(lock);
+		return false;
+	}
+
+	return true;
+}
+EXPORT_SYMBOL(refcount_dec_and_ww_mutex_lock);
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v15 11/23] dma-resv: Add kref_put_dma_resv()
  2023-08-27 17:54 [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Dmitry Osipenko
                   ` (9 preceding siblings ...)
  2023-08-27 17:54 ` [PATCH v15 10/23] locking/refcount, kref: Add kref_put_ww_mutex() Dmitry Osipenko
@ 2023-08-27 17:54 ` Dmitry Osipenko
  2023-08-28 10:21   ` Christian König
  2023-08-27 17:54 ` [PATCH v15 12/23] drm/shmem-helper: Add and use pages_pin_count Dmitry Osipenko
                   ` (12 subsequent siblings)
  23 siblings, 1 reply; 53+ messages in thread
From: Dmitry Osipenko @ 2023-08-27 17:54 UTC (permalink / raw)
  To: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Boris Brezillon, Emma Anholt, Melissa Wen, Will Deacon,
	Peter Zijlstra, Boqun Feng, Mark Rutland
  Cc: dri-devel, linux-kernel, kernel, virtualization, intel-gfx

Add simple kref_put_dma_resv() helper that wraps around kref_put_ww_mutex()
for drivers that needs to lock dma-resv on kref_put().

It's not possible to easily add this helper to kref.h because of the
headers inclusion dependency, hence add it to dma-resv.h.

Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
---
 include/linux/dma-resv.h | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/include/linux/dma-resv.h b/include/linux/dma-resv.h
index 8d0e34dad446..c5cf302e4194 100644
--- a/include/linux/dma-resv.h
+++ b/include/linux/dma-resv.h
@@ -41,6 +41,7 @@
 
 #include <linux/ww_mutex.h>
 #include <linux/dma-fence.h>
+#include <linux/kref.h>
 #include <linux/slab.h>
 #include <linux/seqlock.h>
 #include <linux/rcupdate.h>
@@ -464,6 +465,14 @@ static inline void dma_resv_unlock(struct dma_resv *obj)
 	ww_mutex_unlock(&obj->lock);
 }
 
+static inline int kref_put_dma_resv(struct kref *kref,
+				    void (*release)(struct kref *kref),
+				    struct dma_resv *resv,
+				    struct ww_acquire_ctx *ctx)
+{
+	return kref_put_ww_mutex(kref, release, &resv->lock, ctx);
+}
+
 void dma_resv_init(struct dma_resv *obj);
 void dma_resv_fini(struct dma_resv *obj);
 int dma_resv_reserve_fences(struct dma_resv *obj, unsigned int num_fences);
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v15 12/23] drm/shmem-helper: Add and use pages_pin_count
  2023-08-27 17:54 [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Dmitry Osipenko
                   ` (10 preceding siblings ...)
  2023-08-27 17:54 ` [PATCH v15 11/23] dma-resv: Add kref_put_dma_resv() Dmitry Osipenko
@ 2023-08-27 17:54 ` Dmitry Osipenko
  2023-08-28  9:38   ` Boris Brezillon
  2023-08-28 11:46   ` Boris Brezillon
  2023-08-27 17:54 ` [PATCH v15 13/23] drm/shmem-helper: Use kref for pages_use_count Dmitry Osipenko
                   ` (11 subsequent siblings)
  23 siblings, 2 replies; 53+ messages in thread
From: Dmitry Osipenko @ 2023-08-27 17:54 UTC (permalink / raw)
  To: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Boris Brezillon, Emma Anholt, Melissa Wen, Will Deacon,
	Peter Zijlstra, Boqun Feng, Mark Rutland
  Cc: dri-devel, linux-kernel, kernel, virtualization, intel-gfx

Add separate pages_pin_count for tracking of whether drm-shmem pages are
moveable or not. With the addition of memory shrinker support to drm-shmem,
the pages_use_count will no longer determine whether pages are hard-pinned
in memory, but whether pages exit and are soft-pinned (and could be swapped
out). The pages_pin_count > 1 will hard-pin pages in memory.

Suggested-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
---
 drivers/gpu/drm/drm_gem_shmem_helper.c | 22 +++++++++++++++++-----
 include/drm/drm_gem_shmem_helper.h     | 10 ++++++++++
 2 files changed, 27 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
index d545d3d227d7..1a7e5c332fd8 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -234,14 +234,22 @@ static int drm_gem_shmem_pin_locked(struct drm_gem_shmem_object *shmem)
 
 	dma_resv_assert_held(shmem->base.resv);
 
+	if (kref_get_unless_zero(&shmem->pages_pin_count))
+		return 0;
+
 	ret = drm_gem_shmem_get_pages_locked(shmem);
+	if (!ret)
+		kref_init(&shmem->pages_pin_count);
 
 	return ret;
 }
 
-static void drm_gem_shmem_unpin_locked(struct drm_gem_shmem_object *shmem)
+static void drm_gem_shmem_kref_unpin_pages(struct kref *kref)
 {
-	dma_resv_assert_held(shmem->base.resv);
+	struct drm_gem_shmem_object *shmem;
+
+	shmem = container_of(kref, struct drm_gem_shmem_object,
+			     pages_pin_count);
 
 	drm_gem_shmem_put_pages_locked(shmem);
 }
@@ -263,6 +271,9 @@ int drm_gem_shmem_pin(struct drm_gem_shmem_object *shmem)
 
 	drm_WARN_ON(obj->dev, obj->import_attach);
 
+	if (kref_get_unless_zero(&shmem->pages_pin_count))
+		return 0;
+
 	ret = dma_resv_lock_interruptible(shmem->base.resv, NULL);
 	if (ret)
 		return ret;
@@ -286,9 +297,10 @@ void drm_gem_shmem_unpin(struct drm_gem_shmem_object *shmem)
 
 	drm_WARN_ON(obj->dev, obj->import_attach);
 
-	dma_resv_lock(shmem->base.resv, NULL);
-	drm_gem_shmem_unpin_locked(shmem);
-	dma_resv_unlock(shmem->base.resv);
+	if (kref_put_dma_resv(&shmem->pages_pin_count,
+			      drm_gem_shmem_kref_unpin_pages,
+			      obj->resv, NULL))
+		dma_resv_unlock(obj->resv);
 }
 EXPORT_SYMBOL_GPL(drm_gem_shmem_unpin);
 
diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h
index ec2d8b24e3cf..afb7cd671e2a 100644
--- a/include/drm/drm_gem_shmem_helper.h
+++ b/include/drm/drm_gem_shmem_helper.h
@@ -39,6 +39,16 @@ struct drm_gem_shmem_object {
 	 */
 	unsigned int pages_use_count;
 
+	/**
+	 * @pages_pin_count:
+	 *
+	 * Reference count on the pinned pages table.
+	 * The pages allowed to be evicted and purged by memory
+	 * shrinker only when the count is zero, otherwise pages
+	 * are hard-pinned in memory.
+	 */
+	struct kref pages_pin_count;
+
 	/**
 	 * @madv: State for madvise
 	 *
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v15 13/23] drm/shmem-helper: Use kref for pages_use_count
  2023-08-27 17:54 [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Dmitry Osipenko
                   ` (11 preceding siblings ...)
  2023-08-27 17:54 ` [PATCH v15 12/23] drm/shmem-helper: Add and use pages_pin_count Dmitry Osipenko
@ 2023-08-27 17:54 ` Dmitry Osipenko
  2023-08-27 17:54 ` [PATCH v15 14/23] drm/shmem-helper: Add and use lockless drm_gem_shmem_get_pages() Dmitry Osipenko
                   ` (10 subsequent siblings)
  23 siblings, 0 replies; 53+ messages in thread
From: Dmitry Osipenko @ 2023-08-27 17:54 UTC (permalink / raw)
  To: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Boris Brezillon, Emma Anholt, Melissa Wen, Will Deacon,
	Peter Zijlstra, Boqun Feng, Mark Rutland
  Cc: dri-devel, linux-kernel, kernel, virtualization, intel-gfx

Use atomic kref helper for pages_use_count to optimize pin/unpin functions
by skipping reservation locking while GEM's pin refcount > 1.

Suggested-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
---
 drivers/gpu/drm/drm_gem_shmem_helper.c  | 48 ++++++++++++++-----------
 drivers/gpu/drm/lima/lima_gem.c         |  2 +-
 drivers/gpu/drm/panfrost/panfrost_mmu.c |  2 +-
 include/drm/drm_gem_shmem_helper.h      |  2 +-
 4 files changed, 30 insertions(+), 24 deletions(-)

diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
index 1a7e5c332fd8..5a2e37b3e51d 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -155,7 +155,7 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
 		if (shmem->got_sgt)
 			drm_gem_shmem_put_pages_locked(shmem);
 
-		drm_WARN_ON(obj->dev, shmem->pages_use_count);
+		drm_WARN_ON(obj->dev, kref_read(&shmem->pages_use_count));
 
 		dma_resv_unlock(shmem->base.resv);
 	}
@@ -172,14 +172,13 @@ static int drm_gem_shmem_get_pages_locked(struct drm_gem_shmem_object *shmem)
 
 	dma_resv_assert_held(shmem->base.resv);
 
-	if (shmem->pages_use_count++ > 0)
+	if (kref_get_unless_zero(&shmem->pages_use_count))
 		return 0;
 
 	pages = drm_gem_get_pages(obj);
 	if (IS_ERR(pages)) {
 		drm_dbg_kms(obj->dev, "Failed to get pages (%ld)\n",
 			    PTR_ERR(pages));
-		shmem->pages_use_count = 0;
 		return PTR_ERR(pages);
 	}
 
@@ -195,26 +194,20 @@ static int drm_gem_shmem_get_pages_locked(struct drm_gem_shmem_object *shmem)
 
 	shmem->pages = pages;
 
+	kref_init(&shmem->pages_use_count);
+
 	return 0;
 }
 
-/*
- * drm_gem_shmem_put_pages_locked - Decrease use count on the backing pages for a shmem GEM object
- * @shmem: shmem GEM object
- *
- * This function decreases the use count and puts the backing pages when use drops to zero.
- */
-void drm_gem_shmem_put_pages_locked(struct drm_gem_shmem_object *shmem)
-{
-	struct drm_gem_object *obj = &shmem->base;
-
-	dma_resv_assert_held(shmem->base.resv);
 
-	if (drm_WARN_ON_ONCE(obj->dev, !shmem->pages_use_count))
-		return;
+static void drm_gem_shmem_kref_release_pages(struct kref *kref)
+{
+	struct drm_gem_shmem_object *shmem;
+	struct drm_gem_object *obj;
 
-	if (--shmem->pages_use_count > 0)
-		return;
+	shmem = container_of(kref, struct drm_gem_shmem_object,
+			     pages_use_count);
+	obj = &shmem->base;
 
 #ifdef CONFIG_X86
 	if (shmem->map_wc)
@@ -226,6 +219,19 @@ void drm_gem_shmem_put_pages_locked(struct drm_gem_shmem_object *shmem)
 			  shmem->pages_mark_accessed_on_put);
 	shmem->pages = NULL;
 }
+
+/*
+ * drm_gem_shmem_put_pages_locked - Decrease use count on the backing pages for a shmem GEM object
+ * @shmem: shmem GEM object
+ *
+ * This function decreases the use count and puts the backing pages when use drops to zero.
+ */
+void drm_gem_shmem_put_pages_locked(struct drm_gem_shmem_object *shmem)
+{
+	dma_resv_assert_held(shmem->base.resv);
+
+	kref_put(&shmem->pages_use_count, drm_gem_shmem_kref_release_pages);
+}
 EXPORT_SYMBOL_GPL(drm_gem_shmem_put_pages_locked);
 
 static int drm_gem_shmem_pin_locked(struct drm_gem_shmem_object *shmem)
@@ -556,8 +562,8 @@ static void drm_gem_shmem_vm_open(struct vm_area_struct *vma)
 	 * mmap'd, vm_open() just grabs an additional reference for the new
 	 * mm the vma is getting copied into (ie. on fork()).
 	 */
-	if (!drm_WARN_ON_ONCE(obj->dev, !shmem->pages_use_count))
-		shmem->pages_use_count++;
+	drm_WARN_ON_ONCE(obj->dev,
+			 !kref_get_unless_zero(&shmem->pages_use_count));
 
 	dma_resv_unlock(shmem->base.resv);
 
@@ -638,7 +644,7 @@ void drm_gem_shmem_print_info(const struct drm_gem_shmem_object *shmem,
 	if (shmem->base.import_attach)
 		return;
 
-	drm_printf_indent(p, indent, "pages_use_count=%u\n", shmem->pages_use_count);
+	drm_printf_indent(p, indent, "pages_use_count=%u\n", kref_read(&shmem->pages_use_count));
 	drm_printf_indent(p, indent, "vmap_use_count=%u\n", shmem->vmap_use_count);
 	drm_printf_indent(p, indent, "vaddr=%p\n", shmem->vaddr);
 }
diff --git a/drivers/gpu/drm/lima/lima_gem.c b/drivers/gpu/drm/lima/lima_gem.c
index 7d74c71f5558..a5f015d188cd 100644
--- a/drivers/gpu/drm/lima/lima_gem.c
+++ b/drivers/gpu/drm/lima/lima_gem.c
@@ -47,7 +47,7 @@ int lima_heap_alloc(struct lima_bo *bo, struct lima_vm *vm)
 		}
 
 		bo->base.pages = pages;
-		bo->base.pages_use_count = 1;
+		kref_init(&bo->base.pages_use_count);
 
 		mapping_set_unevictable(mapping);
 	}
diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c
index 7771769f0ce0..c9ac9d361864 100644
--- a/drivers/gpu/drm/panfrost/panfrost_mmu.c
+++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c
@@ -487,7 +487,7 @@ static int panfrost_mmu_map_fault_addr(struct panfrost_device *pfdev, int as,
 			goto err_unlock;
 		}
 		bo->base.pages = pages;
-		bo->base.pages_use_count = 1;
+		kref_init(&bo->base.pages_use_count);
 	} else {
 		pages = bo->base.pages;
 		if (pages[page_offset]) {
diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h
index afb7cd671e2a..a5a3c193cc8f 100644
--- a/include/drm/drm_gem_shmem_helper.h
+++ b/include/drm/drm_gem_shmem_helper.h
@@ -37,7 +37,7 @@ struct drm_gem_shmem_object {
 	 * Reference count on the pages table.
 	 * The pages are put when the count reaches zero.
 	 */
-	unsigned int pages_use_count;
+	struct kref pages_use_count;
 
 	/**
 	 * @pages_pin_count:
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v15 14/23] drm/shmem-helper: Add and use lockless drm_gem_shmem_get_pages()
  2023-08-27 17:54 [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Dmitry Osipenko
                   ` (12 preceding siblings ...)
  2023-08-27 17:54 ` [PATCH v15 13/23] drm/shmem-helper: Use kref for pages_use_count Dmitry Osipenko
@ 2023-08-27 17:54 ` Dmitry Osipenko
  2023-08-27 17:54 ` [PATCH v15 15/23] drm/shmem-helper: Switch drm_gem_shmem_vmap/vunmap to use pin/unpin Dmitry Osipenko
                   ` (9 subsequent siblings)
  23 siblings, 0 replies; 53+ messages in thread
From: Dmitry Osipenko @ 2023-08-27 17:54 UTC (permalink / raw)
  To: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Boris Brezillon, Emma Anholt, Melissa Wen, Will Deacon,
	Peter Zijlstra, Boqun Feng, Mark Rutland
  Cc: dri-devel, linux-kernel, kernel, virtualization, intel-gfx

Add lockless drm_gem_shmem_get_pages() helper that skips taking reservation
lock if pages_use_count is non-zero, leveraging from atomicity of the kref
counter. Make drm_gem_shmem_mmap() to utilize the new helper.

Suggested-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
---
 drivers/gpu/drm/drm_gem_shmem_helper.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
index 5a2e37b3e51d..f386289c24fc 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -234,6 +234,20 @@ void drm_gem_shmem_put_pages_locked(struct drm_gem_shmem_object *shmem)
 }
 EXPORT_SYMBOL_GPL(drm_gem_shmem_put_pages_locked);
 
+static int drm_gem_shmem_get_pages(struct drm_gem_shmem_object *shmem)
+{
+	int ret;
+
+	if (kref_get_unless_zero(&shmem->pages_use_count))
+		return 0;
+
+	dma_resv_lock(shmem->base.resv, NULL);
+	ret = drm_gem_shmem_get_pages_locked(shmem);
+	dma_resv_unlock(shmem->base.resv);
+
+	return ret;
+}
+
 static int drm_gem_shmem_pin_locked(struct drm_gem_shmem_object *shmem)
 {
 	int ret;
@@ -616,10 +630,7 @@ int drm_gem_shmem_mmap(struct drm_gem_shmem_object *shmem, struct vm_area_struct
 		return ret;
 	}
 
-	dma_resv_lock(shmem->base.resv, NULL);
-	ret = drm_gem_shmem_get_pages_locked(shmem);
-	dma_resv_unlock(shmem->base.resv);
-
+	ret = drm_gem_shmem_get_pages(shmem);
 	if (ret)
 		return ret;
 
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v15 15/23] drm/shmem-helper: Switch drm_gem_shmem_vmap/vunmap to use pin/unpin
  2023-08-27 17:54 [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Dmitry Osipenko
                   ` (13 preceding siblings ...)
  2023-08-27 17:54 ` [PATCH v15 14/23] drm/shmem-helper: Add and use lockless drm_gem_shmem_get_pages() Dmitry Osipenko
@ 2023-08-27 17:54 ` Dmitry Osipenko
  2023-08-27 17:54 ` [PATCH v15 16/23] drm/shmem-helper: Use kref for vmap_use_count Dmitry Osipenko
                   ` (8 subsequent siblings)
  23 siblings, 0 replies; 53+ messages in thread
From: Dmitry Osipenko @ 2023-08-27 17:54 UTC (permalink / raw)
  To: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Boris Brezillon, Emma Anholt, Melissa Wen, Will Deacon,
	Peter Zijlstra, Boqun Feng, Mark Rutland
  Cc: dri-devel, linux-kernel, kernel, virtualization, intel-gfx

The vmapped pages shall be pinned in memory and previously get/put_pages()
were implicitly hard-pinning/unpinning the pages. This will no longer be
the case with addition of memory shrinker because pages_use_count > 0 won't
determine anymore whether pages are hard-pinned (they will be soft-pinned),
while the new pages_pin_count will do the hard-pinning. Switch the
vmap/vunmap() to use pin/unpin() functions in a preparation of addition
of the memory shrinker support to drm-shmem.

Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
---
 drivers/gpu/drm/drm_gem_shmem_helper.c | 13 ++++++++++---
 include/drm/drm_gem_shmem_helper.h     |  2 +-
 2 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
index f386289c24fc..17a0177acb5d 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -274,6 +274,13 @@ static void drm_gem_shmem_kref_unpin_pages(struct kref *kref)
 	drm_gem_shmem_put_pages_locked(shmem);
 }
 
+static void drm_gem_shmem_unpin_locked(struct drm_gem_shmem_object *shmem)
+{
+	dma_resv_assert_held(shmem->base.resv);
+
+	kref_put(&shmem->pages_pin_count, drm_gem_shmem_kref_unpin_pages);
+}
+
 /**
  * drm_gem_shmem_pin - Pin backing pages for a shmem GEM object
  * @shmem: shmem GEM object
@@ -357,7 +364,7 @@ int drm_gem_shmem_vmap_locked(struct drm_gem_shmem_object *shmem,
 			return 0;
 		}
 
-		ret = drm_gem_shmem_get_pages_locked(shmem);
+		ret = drm_gem_shmem_pin_locked(shmem);
 		if (ret)
 			goto err_zero_use;
 
@@ -380,7 +387,7 @@ int drm_gem_shmem_vmap_locked(struct drm_gem_shmem_object *shmem,
 
 err_put_pages:
 	if (!obj->import_attach)
-		drm_gem_shmem_put_pages_locked(shmem);
+		drm_gem_shmem_unpin_locked(shmem);
 err_zero_use:
 	shmem->vmap_use_count = 0;
 
@@ -417,7 +424,7 @@ void drm_gem_shmem_vunmap_locked(struct drm_gem_shmem_object *shmem,
 			return;
 
 		vunmap(shmem->vaddr);
-		drm_gem_shmem_put_pages_locked(shmem);
+		drm_gem_shmem_unpin_locked(shmem);
 	}
 
 	shmem->vaddr = NULL;
diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h
index a5a3c193cc8f..400ecd63f45f 100644
--- a/include/drm/drm_gem_shmem_helper.h
+++ b/include/drm/drm_gem_shmem_helper.h
@@ -137,7 +137,7 @@ int drm_gem_shmem_madvise_locked(struct drm_gem_shmem_object *shmem, int madv);
 static inline bool drm_gem_shmem_is_purgeable(struct drm_gem_shmem_object *shmem)
 {
 	return (shmem->madv > 0) &&
-		!shmem->vmap_use_count && shmem->sgt &&
+		!kref_read(&shmem->pages_pin_count) && shmem->sgt &&
 		!shmem->base.dma_buf && !shmem->base.import_attach;
 }
 
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v15 16/23] drm/shmem-helper: Use kref for vmap_use_count
  2023-08-27 17:54 [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Dmitry Osipenko
                   ` (14 preceding siblings ...)
  2023-08-27 17:54 ` [PATCH v15 15/23] drm/shmem-helper: Switch drm_gem_shmem_vmap/vunmap to use pin/unpin Dmitry Osipenko
@ 2023-08-27 17:54 ` Dmitry Osipenko
  2023-08-28 10:00   ` Boris Brezillon
  2023-08-27 17:54 ` [PATCH v15 17/23] drm/shmem-helper: Add and use drm_gem_shmem_resv_assert_held() helper Dmitry Osipenko
                   ` (7 subsequent siblings)
  23 siblings, 1 reply; 53+ messages in thread
From: Dmitry Osipenko @ 2023-08-27 17:54 UTC (permalink / raw)
  To: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Boris Brezillon, Emma Anholt, Melissa Wen, Will Deacon,
	Peter Zijlstra, Boqun Feng, Mark Rutland
  Cc: dri-devel, linux-kernel, kernel, virtualization, intel-gfx

Use kref helper for vmap_use_count to make refcounting consistent with
pages_use_count and pages_pin_count that use kref. This will allow to
optimize unlocked vmappings by skipping reservation locking if refcnt > 1.

Suggested-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
---
 drivers/gpu/drm/drm_gem_shmem_helper.c | 37 ++++++++++++++------------
 include/drm/drm_gem_shmem_helper.h     |  2 +-
 2 files changed, 21 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
index 17a0177acb5d..d96fee3d6166 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -144,7 +144,7 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
 	} else if (!shmem->imported_sgt) {
 		dma_resv_lock(shmem->base.resv, NULL);
 
-		drm_WARN_ON(obj->dev, shmem->vmap_use_count);
+		drm_WARN_ON(obj->dev, kref_read(&shmem->vmap_use_count));
 
 		if (shmem->sgt) {
 			dma_unmap_sgtable(obj->dev->dev, shmem->sgt,
@@ -359,23 +359,25 @@ int drm_gem_shmem_vmap_locked(struct drm_gem_shmem_object *shmem,
 
 		dma_resv_assert_held(shmem->base.resv);
 
-		if (shmem->vmap_use_count++ > 0) {
+		if (kref_get_unless_zero(&shmem->vmap_use_count)) {
 			iosys_map_set_vaddr(map, shmem->vaddr);
 			return 0;
 		}
 
 		ret = drm_gem_shmem_pin_locked(shmem);
 		if (ret)
-			goto err_zero_use;
+			return ret;
 
 		if (shmem->map_wc)
 			prot = pgprot_writecombine(prot);
 		shmem->vaddr = vmap(shmem->pages, obj->size >> PAGE_SHIFT,
 				    VM_MAP, prot);
-		if (!shmem->vaddr)
+		if (!shmem->vaddr) {
 			ret = -ENOMEM;
-		else
+		} else {
 			iosys_map_set_vaddr(map, shmem->vaddr);
+			kref_init(&shmem->vmap_use_count);
+		}
 	}
 
 	if (ret) {
@@ -388,13 +390,22 @@ int drm_gem_shmem_vmap_locked(struct drm_gem_shmem_object *shmem,
 err_put_pages:
 	if (!obj->import_attach)
 		drm_gem_shmem_unpin_locked(shmem);
-err_zero_use:
-	shmem->vmap_use_count = 0;
 
 	return ret;
 }
 EXPORT_SYMBOL_GPL(drm_gem_shmem_vmap_locked);
 
+static void drm_gem_shmem_kref_vunmap(struct kref *kref)
+{
+	struct drm_gem_shmem_object *shmem;
+
+	shmem = container_of(kref, struct drm_gem_shmem_object,
+			     vmap_use_count);
+
+	vunmap(shmem->vaddr);
+	drm_gem_shmem_unpin_locked(shmem);
+}
+
 /*
  * drm_gem_shmem_vunmap_locked - Unmap a virtual mapping for a shmem GEM object
  * @shmem: shmem GEM object
@@ -416,15 +427,7 @@ void drm_gem_shmem_vunmap_locked(struct drm_gem_shmem_object *shmem,
 		dma_buf_vunmap(obj->import_attach->dmabuf, map);
 	} else {
 		dma_resv_assert_held(shmem->base.resv);
-
-		if (drm_WARN_ON_ONCE(obj->dev, !shmem->vmap_use_count))
-			return;
-
-		if (--shmem->vmap_use_count > 0)
-			return;
-
-		vunmap(shmem->vaddr);
-		drm_gem_shmem_unpin_locked(shmem);
+		kref_put(&shmem->vmap_use_count, drm_gem_shmem_kref_vunmap);
 	}
 
 	shmem->vaddr = NULL;
@@ -663,7 +666,7 @@ void drm_gem_shmem_print_info(const struct drm_gem_shmem_object *shmem,
 		return;
 
 	drm_printf_indent(p, indent, "pages_use_count=%u\n", kref_read(&shmem->pages_use_count));
-	drm_printf_indent(p, indent, "vmap_use_count=%u\n", shmem->vmap_use_count);
+	drm_printf_indent(p, indent, "vmap_use_count=%u\n", kref_read(&shmem->vmap_use_count));
 	drm_printf_indent(p, indent, "vaddr=%p\n", shmem->vaddr);
 }
 EXPORT_SYMBOL_GPL(drm_gem_shmem_print_info);
diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h
index 400ecd63f45f..0e0ccd380f66 100644
--- a/include/drm/drm_gem_shmem_helper.h
+++ b/include/drm/drm_gem_shmem_helper.h
@@ -81,7 +81,7 @@ struct drm_gem_shmem_object {
 	 * Reference count on the virtual address.
 	 * The address are un-mapped when the count reaches zero.
 	 */
-	unsigned int vmap_use_count;
+	struct kref vmap_use_count;
 
 	/**
 	 * @got_sgt:
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v15 17/23] drm/shmem-helper: Add and use drm_gem_shmem_resv_assert_held() helper
  2023-08-27 17:54 [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Dmitry Osipenko
                   ` (15 preceding siblings ...)
  2023-08-27 17:54 ` [PATCH v15 16/23] drm/shmem-helper: Use kref for vmap_use_count Dmitry Osipenko
@ 2023-08-27 17:54 ` Dmitry Osipenko
  2023-08-28 10:12   ` Boris Brezillon
  2023-08-27 17:54 ` [PATCH v15 18/23] drm/shmem-helper: Add memory shrinker Dmitry Osipenko
                   ` (6 subsequent siblings)
  23 siblings, 1 reply; 53+ messages in thread
From: Dmitry Osipenko @ 2023-08-27 17:54 UTC (permalink / raw)
  To: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Boris Brezillon, Emma Anholt, Melissa Wen, Will Deacon,
	Peter Zijlstra, Boqun Feng, Mark Rutland
  Cc: dri-devel, linux-kernel, kernel, virtualization, intel-gfx

In a preparation of adding drm-shmem memory shrinker, move all reservation
locking lockdep checks to use new drm_gem_shmem_resv_assert_held() that
will resolve spurious lockdep warning about wrong locking order vs
fs_reclam code paths during freeing of shmem GEM, where lockdep isn't
aware that it's impossible to have locking contention with the fs_reclam
at this special time.

Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
---
 drivers/gpu/drm/drm_gem_shmem_helper.c | 37 +++++++++++++++++---------
 1 file changed, 25 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
index d96fee3d6166..ca5da976aafa 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -128,6 +128,23 @@ struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t
 }
 EXPORT_SYMBOL_GPL(drm_gem_shmem_create);
 
+static void drm_gem_shmem_resv_assert_held(struct drm_gem_shmem_object *shmem)
+{
+	/*
+	 * Destroying the object is a special case.. drm_gem_shmem_free()
+	 * calls many things that WARN_ON if the obj lock is not held.  But
+	 * acquiring the obj lock in drm_gem_shmem_free() can cause a locking
+	 * order inversion between reservation_ww_class_mutex and fs_reclaim.
+	 *
+	 * This deadlock is not actually possible, because no one should
+	 * be already holding the lock when drm_gem_shmem_free() is called.
+	 * Unfortunately lockdep is not aware of this detail.  So when the
+	 * refcount drops to zero, we pretend it is already locked.
+	 */
+	if (kref_read(&shmem->base.refcount))
+		drm_gem_shmem_resv_assert_held(shmem);
+}
+
 /**
  * drm_gem_shmem_free - Free resources associated with a shmem GEM object
  * @shmem: shmem GEM object to free
@@ -142,8 +159,6 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
 	if (obj->import_attach) {
 		drm_prime_gem_destroy(obj, shmem->sgt);
 	} else if (!shmem->imported_sgt) {
-		dma_resv_lock(shmem->base.resv, NULL);
-
 		drm_WARN_ON(obj->dev, kref_read(&shmem->vmap_use_count));
 
 		if (shmem->sgt) {
@@ -156,8 +171,6 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
 			drm_gem_shmem_put_pages_locked(shmem);
 
 		drm_WARN_ON(obj->dev, kref_read(&shmem->pages_use_count));
-
-		dma_resv_unlock(shmem->base.resv);
 	}
 
 	drm_gem_object_release(obj);
@@ -170,7 +183,7 @@ static int drm_gem_shmem_get_pages_locked(struct drm_gem_shmem_object *shmem)
 	struct drm_gem_object *obj = &shmem->base;
 	struct page **pages;
 
-	dma_resv_assert_held(shmem->base.resv);
+	drm_gem_shmem_resv_assert_held(shmem);
 
 	if (kref_get_unless_zero(&shmem->pages_use_count))
 		return 0;
@@ -228,7 +241,7 @@ static void drm_gem_shmem_kref_release_pages(struct kref *kref)
  */
 void drm_gem_shmem_put_pages_locked(struct drm_gem_shmem_object *shmem)
 {
-	dma_resv_assert_held(shmem->base.resv);
+	drm_gem_shmem_resv_assert_held(shmem);
 
 	kref_put(&shmem->pages_use_count, drm_gem_shmem_kref_release_pages);
 }
@@ -252,7 +265,7 @@ static int drm_gem_shmem_pin_locked(struct drm_gem_shmem_object *shmem)
 {
 	int ret;
 
-	dma_resv_assert_held(shmem->base.resv);
+	drm_gem_shmem_resv_assert_held(shmem);
 
 	if (kref_get_unless_zero(&shmem->pages_pin_count))
 		return 0;
@@ -276,7 +289,7 @@ static void drm_gem_shmem_kref_unpin_pages(struct kref *kref)
 
 static void drm_gem_shmem_unpin_locked(struct drm_gem_shmem_object *shmem)
 {
-	dma_resv_assert_held(shmem->base.resv);
+	drm_gem_shmem_resv_assert_held(shmem);
 
 	kref_put(&shmem->pages_pin_count, drm_gem_shmem_kref_unpin_pages);
 }
@@ -357,7 +370,7 @@ int drm_gem_shmem_vmap_locked(struct drm_gem_shmem_object *shmem,
 	} else {
 		pgprot_t prot = PAGE_KERNEL;
 
-		dma_resv_assert_held(shmem->base.resv);
+		drm_gem_shmem_resv_assert_held(shmem);
 
 		if (kref_get_unless_zero(&shmem->vmap_use_count)) {
 			iosys_map_set_vaddr(map, shmem->vaddr);
@@ -426,7 +439,7 @@ void drm_gem_shmem_vunmap_locked(struct drm_gem_shmem_object *shmem,
 	if (obj->import_attach) {
 		dma_buf_vunmap(obj->import_attach->dmabuf, map);
 	} else {
-		dma_resv_assert_held(shmem->base.resv);
+		drm_gem_shmem_resv_assert_held(shmem);
 		kref_put(&shmem->vmap_use_count, drm_gem_shmem_kref_vunmap);
 	}
 
@@ -462,7 +475,7 @@ drm_gem_shmem_create_with_handle(struct drm_file *file_priv,
  */
 int drm_gem_shmem_madvise_locked(struct drm_gem_shmem_object *shmem, int madv)
 {
-	dma_resv_assert_held(shmem->base.resv);
+	drm_gem_shmem_resv_assert_held(shmem);
 
 	if (shmem->madv >= 0)
 		shmem->madv = madv;
@@ -478,7 +491,7 @@ void drm_gem_shmem_purge_locked(struct drm_gem_shmem_object *shmem)
 	struct drm_gem_object *obj = &shmem->base;
 	struct drm_device *dev = obj->dev;
 
-	dma_resv_assert_held(shmem->base.resv);
+	drm_gem_shmem_resv_assert_held(shmem);
 
 	drm_WARN_ON(obj->dev, !drm_gem_shmem_is_purgeable(shmem));
 
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v15 18/23] drm/shmem-helper: Add memory shrinker
  2023-08-27 17:54 [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Dmitry Osipenko
                   ` (16 preceding siblings ...)
  2023-08-27 17:54 ` [PATCH v15 17/23] drm/shmem-helper: Add and use drm_gem_shmem_resv_assert_held() helper Dmitry Osipenko
@ 2023-08-27 17:54 ` Dmitry Osipenko
  2023-08-27 17:54 ` [PATCH v15 19/23] drm/shmem-helper: Export drm_gem_shmem_get_pages_sgt_locked() Dmitry Osipenko
                   ` (5 subsequent siblings)
  23 siblings, 0 replies; 53+ messages in thread
From: Dmitry Osipenko @ 2023-08-27 17:54 UTC (permalink / raw)
  To: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Boris Brezillon, Emma Anholt, Melissa Wen, Will Deacon,
	Peter Zijlstra, Boqun Feng, Mark Rutland
  Cc: dri-devel, linux-kernel, kernel, virtualization, intel-gfx

Introduce common drm-shmem shrinker for DRM drivers.

To start using drm-shmem shrinker drivers should do the following:

1. Implement evict() callback of GEM object where driver should check
   whether object is purgeable or evictable using drm-shmem helpers and
   perform the shrinking action

2. Initialize drm-shmem internals using drmm_gem_shmem_init(drm_device),
   which will register drm-shmem shrinker

3. Implement madvise IOCTL that will use drm_gem_shmem_madvise()

Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
---
 drivers/gpu/drm/drm_gem_shmem_helper.c        | 415 +++++++++++++++++-
 .../gpu/drm/panfrost/panfrost_gem_shrinker.c  |   9 +-
 include/drm/drm_device.h                      |  10 +-
 include/drm/drm_gem_shmem_helper.h            |  71 ++-
 4 files changed, 474 insertions(+), 31 deletions(-)

diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
index ca5da976aafa..f0f708e0ff00 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -20,6 +20,7 @@
 #include <drm/drm_device.h>
 #include <drm/drm_drv.h>
 #include <drm/drm_gem_shmem_helper.h>
+#include <drm/drm_managed.h>
 #include <drm/drm_prime.h>
 #include <drm/drm_print.h>
 
@@ -88,8 +89,6 @@ __drm_gem_shmem_create(struct drm_device *dev, size_t size, bool private)
 	if (ret)
 		goto err_release;
 
-	INIT_LIST_HEAD(&shmem->madv_list);
-
 	if (!private) {
 		/*
 		 * Our buffers are kept pinned, so allocating them
@@ -142,7 +141,42 @@ static void drm_gem_shmem_resv_assert_held(struct drm_gem_shmem_object *shmem)
 	 * refcount drops to zero, we pretend it is already locked.
 	 */
 	if (kref_read(&shmem->base.refcount))
-		drm_gem_shmem_resv_assert_held(shmem);
+		dma_resv_assert_held(shmem->base.resv);
+}
+
+static bool drm_gem_shmem_is_evictable(struct drm_gem_shmem_object *shmem)
+{
+	drm_gem_shmem_resv_assert_held(shmem);
+
+	return (shmem->madv >= 0) && shmem->base.funcs->evict &&
+		kref_read(&shmem->pages_use_count) &&
+		!kref_read(&shmem->pages_pin_count) &&
+		!shmem->base.dma_buf && !shmem->base.import_attach &&
+		shmem->sgt && !shmem->evicted;
+}
+
+static void
+drm_gem_shmem_update_pages_state_locked(struct drm_gem_shmem_object *shmem)
+{
+	struct drm_gem_object *obj = &shmem->base;
+	struct drm_gem_shmem *shmem_mm = obj->dev->shmem_mm;
+	struct drm_gem_shmem_shrinker *shmem_shrinker = &shmem_mm->shrinker;
+
+	drm_gem_shmem_resv_assert_held(shmem);
+
+	if (!shmem_shrinker || obj->import_attach)
+		return;
+
+	if (shmem->madv < 0)
+		drm_gem_lru_remove(&shmem->base);
+	else if (drm_gem_shmem_is_evictable(shmem) || drm_gem_shmem_is_purgeable(shmem))
+		drm_gem_lru_move_tail(&shmem_shrinker->lru_evictable, &shmem->base);
+	else if (shmem->evicted)
+		drm_gem_lru_move_tail(&shmem_shrinker->lru_evicted, &shmem->base);
+	else if (!shmem->pages)
+		drm_gem_lru_remove(&shmem->base);
+	else
+		drm_gem_lru_move_tail(&shmem_shrinker->lru_pinned, &shmem->base);
 }
 
 /**
@@ -159,6 +193,9 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
 	if (obj->import_attach) {
 		drm_prime_gem_destroy(obj, shmem->sgt);
 	} else if (!shmem->imported_sgt) {
+		/* take out shmem GEM object from the memory shrinker */
+		drm_gem_shmem_madvise_locked(shmem, -1);
+
 		drm_WARN_ON(obj->dev, kref_read(&shmem->vmap_use_count));
 
 		if (shmem->sgt) {
@@ -178,15 +215,26 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
 }
 EXPORT_SYMBOL_GPL(drm_gem_shmem_free);
 
-static int drm_gem_shmem_get_pages_locked(struct drm_gem_shmem_object *shmem)
+static int
+drm_gem_shmem_acquire_pages(struct drm_gem_shmem_object *shmem, bool init)
 {
 	struct drm_gem_object *obj = &shmem->base;
 	struct page **pages;
 
 	drm_gem_shmem_resv_assert_held(shmem);
 
-	if (kref_get_unless_zero(&shmem->pages_use_count))
+	if (shmem->madv < 0) {
+		drm_WARN_ON(obj->dev, shmem->pages);
+		return -ENOMEM;
+	}
+
+	if (shmem->pages) {
+		drm_WARN_ON(obj->dev, !shmem->evicted);
 		return 0;
+	}
+
+	if (drm_WARN_ON(obj->dev, !(init ^ kref_read(&shmem->pages_use_count))))
+		return -EINVAL;
 
 	pages = drm_gem_get_pages(obj);
 	if (IS_ERR(pages)) {
@@ -207,20 +255,20 @@ static int drm_gem_shmem_get_pages_locked(struct drm_gem_shmem_object *shmem)
 
 	shmem->pages = pages;
 
-	kref_init(&shmem->pages_use_count);
-
 	return 0;
 }
 
-
-static void drm_gem_shmem_kref_release_pages(struct kref *kref)
+static void
+drm_gem_shmem_release_pages_locked(struct drm_gem_shmem_object *shmem)
 {
-	struct drm_gem_shmem_object *shmem;
-	struct drm_gem_object *obj;
+	struct drm_gem_object *obj = &shmem->base;
 
-	shmem = container_of(kref, struct drm_gem_shmem_object,
-			     pages_use_count);
-	obj = &shmem->base;
+	drm_gem_shmem_resv_assert_held(shmem);
+
+	if (!shmem->pages) {
+		drm_WARN_ON(obj->dev, !shmem->evicted && shmem->madv >= 0);
+		return;
+	}
 
 #ifdef CONFIG_X86
 	if (shmem->map_wc)
@@ -233,6 +281,41 @@ static void drm_gem_shmem_kref_release_pages(struct kref *kref)
 	shmem->pages = NULL;
 }
 
+static void drm_gem_shmem_kref_release_pages(struct kref *kref)
+{
+	struct drm_gem_shmem_object *shmem;
+
+	shmem = container_of(kref, struct drm_gem_shmem_object,
+			     pages_use_count);
+
+	drm_gem_shmem_release_pages_locked(shmem);
+
+	drm_gem_shmem_update_pages_state_locked(shmem);
+}
+
+static int drm_gem_shmem_get_pages_locked(struct drm_gem_shmem_object *shmem)
+{
+	int err;
+
+	drm_gem_shmem_resv_assert_held(shmem);
+
+	if (shmem->madv < 0)
+		return -ENOMEM;
+
+	if (kref_get_unless_zero(&shmem->pages_use_count))
+		return 0;
+
+	err = drm_gem_shmem_acquire_pages(shmem, true);
+	if (err)
+		return err;
+
+	kref_init(&shmem->pages_use_count);
+
+	drm_gem_shmem_update_pages_state_locked(shmem);
+
+	return 0;
+}
+
 /*
  * drm_gem_shmem_put_pages_locked - Decrease use count on the backing pages for a shmem GEM object
  * @shmem: shmem GEM object
@@ -271,8 +354,15 @@ static int drm_gem_shmem_pin_locked(struct drm_gem_shmem_object *shmem)
 		return 0;
 
 	ret = drm_gem_shmem_get_pages_locked(shmem);
-	if (!ret)
+	if (!ret) {
+		ret = drm_gem_shmem_swapin_locked(shmem);
+		if (ret) {
+			drm_gem_shmem_put_pages_locked(shmem);
+			return ret;
+		}
+
 		kref_init(&shmem->pages_pin_count);
+	}
 
 	return ret;
 }
@@ -482,29 +572,54 @@ int drm_gem_shmem_madvise_locked(struct drm_gem_shmem_object *shmem, int madv)
 
 	madv = shmem->madv;
 
+	drm_gem_shmem_update_pages_state_locked(shmem);
+
 	return (madv >= 0);
 }
 EXPORT_SYMBOL_GPL(drm_gem_shmem_madvise_locked);
 
-void drm_gem_shmem_purge_locked(struct drm_gem_shmem_object *shmem)
+int drm_gem_shmem_madvise(struct drm_gem_shmem_object *shmem, int madv)
+{
+	struct drm_gem_object *obj = &shmem->base;
+	int ret;
+
+	ret = dma_resv_lock_interruptible(obj->resv, NULL);
+	if (ret)
+		return ret;
+
+	ret = drm_gem_shmem_madvise_locked(shmem, madv);
+	dma_resv_unlock(obj->resv);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(drm_gem_shmem_madvise);
+
+static void drm_gem_shmem_unpin_pages_locked(struct drm_gem_shmem_object *shmem)
 {
 	struct drm_gem_object *obj = &shmem->base;
 	struct drm_device *dev = obj->dev;
 
 	drm_gem_shmem_resv_assert_held(shmem);
 
-	drm_WARN_ON(obj->dev, !drm_gem_shmem_is_purgeable(shmem));
+	if (shmem->evicted)
+		return;
 
 	dma_unmap_sgtable(dev->dev, shmem->sgt, DMA_BIDIRECTIONAL, 0);
+	drm_gem_shmem_release_pages_locked(shmem);
+	drm_vma_node_unmap(&obj->vma_node, dev->anon_inode->i_mapping);
+
 	sg_free_table(shmem->sgt);
 	kfree(shmem->sgt);
 	shmem->sgt = NULL;
+}
 
-	drm_gem_shmem_put_pages_locked(shmem);
+void drm_gem_shmem_purge_locked(struct drm_gem_shmem_object *shmem)
+{
+	struct drm_gem_object *obj = &shmem->base;
 
-	shmem->madv = -1;
+	drm_WARN_ON(obj->dev, !drm_gem_shmem_is_purgeable(shmem));
 
-	drm_vma_node_unmap(&obj->vma_node, dev->anon_inode->i_mapping);
+	drm_gem_shmem_unpin_pages_locked(shmem);
 	drm_gem_free_mmap_offset(obj);
 
 	/* Our goal here is to return as much of the memory as
@@ -515,9 +630,59 @@ void drm_gem_shmem_purge_locked(struct drm_gem_shmem_object *shmem)
 	shmem_truncate_range(file_inode(obj->filp), 0, (loff_t)-1);
 
 	invalidate_mapping_pages(file_inode(obj->filp)->i_mapping, 0, (loff_t)-1);
+
+	shmem->madv = -1;
+	shmem->evicted = false;
+	drm_gem_shmem_update_pages_state_locked(shmem);
 }
 EXPORT_SYMBOL_GPL(drm_gem_shmem_purge_locked);
 
+/**
+ * drm_gem_shmem_swapin_locked() - Moves shmem GEM back to memory and enables
+ *                                 hardware access to the memory.
+ * @shmem: shmem GEM object
+ *
+ * This function moves shmem GEM back to memory if it was previously evicted
+ * by the memory shrinker. The GEM is ready to use on success.
+ *
+ * Returns:
+ * 0 on success or a negative error code on failure.
+ */
+int drm_gem_shmem_swapin_locked(struct drm_gem_shmem_object *shmem)
+{
+	struct drm_gem_object *obj = &shmem->base;
+	struct sg_table *sgt;
+	int err;
+
+	drm_gem_shmem_resv_assert_held(shmem);
+
+	if (shmem->evicted) {
+		err = drm_gem_shmem_acquire_pages(shmem, false);
+		if (err)
+			return err;
+
+		sgt = drm_gem_shmem_get_sg_table(shmem);
+		if (IS_ERR(sgt))
+			return PTR_ERR(sgt);
+
+		err = dma_map_sgtable(obj->dev->dev, sgt,
+				      DMA_BIDIRECTIONAL, 0);
+		if (err) {
+			sg_free_table(sgt);
+			kfree(sgt);
+			return err;
+		}
+
+		shmem->sgt = sgt;
+		shmem->evicted = false;
+
+		drm_gem_shmem_update_pages_state_locked(shmem);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(drm_gem_shmem_swapin_locked);
+
 /**
  * drm_gem_shmem_dumb_create - Create a dumb shmem buffer object
  * @file: DRM file structure to create the dumb buffer for
@@ -564,22 +729,34 @@ static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf)
 	vm_fault_t ret;
 	struct page *page;
 	pgoff_t page_offset;
+	bool pages_unpinned;
+	int err;
 
 	/* We don't use vmf->pgoff since that has the fake offset */
 	page_offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT;
 
 	dma_resv_lock(shmem->base.resv, NULL);
 
-	if (page_offset >= num_pages ||
-	    drm_WARN_ON_ONCE(obj->dev, !shmem->pages) ||
-	    shmem->madv < 0) {
+	/* Sanity-check that we have the pages pointer when it should present */
+	pages_unpinned = (shmem->evicted || shmem->madv < 0 ||
+			  !kref_read(&shmem->pages_use_count));
+	drm_WARN_ON_ONCE(obj->dev, !shmem->pages ^ pages_unpinned);
+
+	if (page_offset >= num_pages || (!shmem->pages && !shmem->evicted)) {
 		ret = VM_FAULT_SIGBUS;
 	} else {
+		err = drm_gem_shmem_swapin_locked(shmem);
+		if (err) {
+			ret = VM_FAULT_OOM;
+			goto unlock;
+		}
+
 		page = shmem->pages[page_offset];
 
 		ret = vmf_insert_pfn(vma, vmf->address, page_to_pfn(page));
 	}
 
+unlock:
 	dma_resv_unlock(shmem->base.resv);
 
 	return ret;
@@ -602,6 +779,7 @@ static void drm_gem_shmem_vm_open(struct vm_area_struct *vma)
 	drm_WARN_ON_ONCE(obj->dev,
 			 !kref_get_unless_zero(&shmem->pages_use_count));
 
+	drm_gem_shmem_update_pages_state_locked(shmem);
 	dma_resv_unlock(shmem->base.resv);
 
 	drm_gem_vm_open(vma);
@@ -680,7 +858,9 @@ void drm_gem_shmem_print_info(const struct drm_gem_shmem_object *shmem,
 
 	drm_printf_indent(p, indent, "pages_use_count=%u\n", kref_read(&shmem->pages_use_count));
 	drm_printf_indent(p, indent, "vmap_use_count=%u\n", kref_read(&shmem->vmap_use_count));
+	drm_printf_indent(p, indent, "evicted=%d\n", shmem->evicted);
 	drm_printf_indent(p, indent, "vaddr=%p\n", shmem->vaddr);
+	drm_printf_indent(p, indent, "madv=%d\n", shmem->madv);
 }
 EXPORT_SYMBOL_GPL(drm_gem_shmem_print_info);
 
@@ -736,6 +916,8 @@ static struct sg_table *drm_gem_shmem_get_pages_sgt_locked(struct drm_gem_shmem_
 	shmem->got_sgt = true;
 	shmem->sgt = sgt;
 
+	drm_gem_shmem_update_pages_state_locked(shmem);
+
 	return sgt;
 
 err_free_sgt:
@@ -764,8 +946,8 @@ static struct sg_table *drm_gem_shmem_get_pages_sgt_locked(struct drm_gem_shmem_
  */
 struct sg_table *drm_gem_shmem_get_pages_sgt(struct drm_gem_shmem_object *shmem)
 {
-	int ret;
 	struct sg_table *sgt;
+	int ret;
 
 	ret = dma_resv_lock_interruptible(shmem->base.resv, NULL);
 	if (ret)
@@ -813,6 +995,191 @@ drm_gem_shmem_prime_import_sg_table(struct drm_device *dev,
 }
 EXPORT_SYMBOL_GPL(drm_gem_shmem_prime_import_sg_table);
 
+static struct drm_gem_shmem_shrinker *
+to_drm_gem_shmem_shrinker(struct shrinker *shrinker)
+{
+	return container_of(shrinker, struct drm_gem_shmem_shrinker, base);
+}
+
+static unsigned long
+drm_gem_shmem_shrinker_count_objects(struct shrinker *shrinker,
+				     struct shrink_control *sc)
+{
+	struct drm_gem_shmem_shrinker *shmem_shrinker =
+					to_drm_gem_shmem_shrinker(shrinker);
+	unsigned long count = shmem_shrinker->lru_evictable.count;
+
+	if (count >= SHRINK_EMPTY)
+		return SHRINK_EMPTY - 1;
+
+	return count ?: SHRINK_EMPTY;
+}
+
+void drm_gem_shmem_evict_locked(struct drm_gem_shmem_object *shmem)
+{
+	struct drm_gem_object *obj = &shmem->base;
+
+	drm_WARN_ON(obj->dev, !drm_gem_shmem_is_evictable(shmem));
+	drm_WARN_ON(obj->dev, shmem->evicted);
+
+	drm_gem_shmem_unpin_pages_locked(shmem);
+
+	shmem->evicted = true;
+	drm_gem_shmem_update_pages_state_locked(shmem);
+}
+EXPORT_SYMBOL_GPL(drm_gem_shmem_evict_locked);
+
+static bool drm_gem_shmem_shrinker_evict_locked(struct drm_gem_object *obj)
+{
+	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
+	int err;
+
+	if (!drm_gem_shmem_is_evictable(shmem) ||
+	    get_nr_swap_pages() < obj->size >> PAGE_SHIFT)
+		return false;
+
+	err = drm_gem_evict_locked(obj);
+	if (err)
+		return false;
+
+	return true;
+}
+
+static bool drm_gem_shmem_shrinker_purge_locked(struct drm_gem_object *obj)
+{
+	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
+	int err;
+
+	if (!drm_gem_shmem_is_purgeable(shmem))
+		return false;
+
+	err = drm_gem_evict_locked(obj);
+	if (err)
+		return false;
+
+	return true;
+}
+
+static unsigned long
+drm_gem_shmem_shrinker_scan_objects(struct shrinker *shrinker,
+				    struct shrink_control *sc)
+{
+	struct drm_gem_shmem_shrinker *shmem_shrinker;
+	unsigned long nr_to_scan = sc->nr_to_scan;
+	unsigned long remaining = 0;
+	unsigned long freed = 0;
+
+	shmem_shrinker = to_drm_gem_shmem_shrinker(shrinker);
+
+	/* purge as many objects as we can */
+	freed += drm_gem_lru_scan(&shmem_shrinker->lru_evictable,
+				  nr_to_scan, &remaining,
+				  drm_gem_shmem_shrinker_purge_locked);
+
+	/* evict as many objects as we can */
+	if (freed < nr_to_scan)
+		freed += drm_gem_lru_scan(&shmem_shrinker->lru_evictable,
+					  nr_to_scan - freed, &remaining,
+					  drm_gem_shmem_shrinker_evict_locked);
+
+	return (freed > 0 && remaining > 0) ? freed : SHRINK_STOP;
+}
+
+static int drm_gem_shmem_shrinker_init(struct drm_gem_shmem *shmem_mm,
+				       const char *shrinker_name)
+{
+	struct drm_gem_shmem_shrinker *shmem_shrinker = &shmem_mm->shrinker;
+	int err;
+
+	shmem_shrinker->base.count_objects = drm_gem_shmem_shrinker_count_objects;
+	shmem_shrinker->base.scan_objects = drm_gem_shmem_shrinker_scan_objects;
+	shmem_shrinker->base.seeks = DEFAULT_SEEKS;
+
+	mutex_init(&shmem_shrinker->lock);
+	drm_gem_lru_init(&shmem_shrinker->lru_evictable, &shmem_shrinker->lock);
+	drm_gem_lru_init(&shmem_shrinker->lru_evicted, &shmem_shrinker->lock);
+	drm_gem_lru_init(&shmem_shrinker->lru_pinned, &shmem_shrinker->lock);
+
+	err = register_shrinker(&shmem_shrinker->base, shrinker_name);
+	if (err) {
+		mutex_destroy(&shmem_shrinker->lock);
+		return err;
+	}
+
+	return 0;
+}
+
+static void drm_gem_shmem_shrinker_release(struct drm_device *dev,
+					   struct drm_gem_shmem *shmem_mm)
+{
+	struct drm_gem_shmem_shrinker *shmem_shrinker = &shmem_mm->shrinker;
+
+	unregister_shrinker(&shmem_shrinker->base);
+	drm_WARN_ON(dev, !list_empty(&shmem_shrinker->lru_evictable.list));
+	drm_WARN_ON(dev, !list_empty(&shmem_shrinker->lru_evicted.list));
+	drm_WARN_ON(dev, !list_empty(&shmem_shrinker->lru_pinned.list));
+	mutex_destroy(&shmem_shrinker->lock);
+}
+
+static int drm_gem_shmem_init(struct drm_device *dev)
+{
+	int err;
+
+	if (drm_WARN_ON(dev, dev->shmem_mm))
+		return -EBUSY;
+
+	dev->shmem_mm = kzalloc(sizeof(*dev->shmem_mm), GFP_KERNEL);
+	if (!dev->shmem_mm)
+		return -ENOMEM;
+
+	err = drm_gem_shmem_shrinker_init(dev->shmem_mm, dev->unique);
+	if (err)
+		goto free_gem_shmem;
+
+	return 0;
+
+free_gem_shmem:
+	kfree(dev->shmem_mm);
+	dev->shmem_mm = NULL;
+
+	return err;
+}
+
+static void drm_gem_shmem_release(struct drm_device *dev, void *ptr)
+{
+	struct drm_gem_shmem *shmem_mm = dev->shmem_mm;
+
+	drm_gem_shmem_shrinker_release(dev, shmem_mm);
+	dev->shmem_mm = NULL;
+	kfree(shmem_mm);
+}
+
+/**
+ * drmm_gem_shmem_init() - Initialize drm-shmem internals
+ * @dev: DRM device
+ *
+ * Cleanup is automatically managed as part of DRM device releasing.
+ * Calling this function multiple times will result in a error.
+ *
+ * Returns:
+ * 0 on success or a negative error code on failure.
+ */
+int drmm_gem_shmem_init(struct drm_device *dev)
+{
+	int err;
+
+	err = drm_gem_shmem_init(dev);
+	if (err)
+		return err;
+
+	err = drmm_add_action_or_reset(dev, drm_gem_shmem_release, NULL);
+	if (err)
+		return err;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(drmm_gem_shmem_init);
+
 MODULE_DESCRIPTION("DRM SHMEM memory-management helpers");
 MODULE_IMPORT_NS(DMA_BUF);
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c b/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
index 72193bd734e1..eb810403b027 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
+++ b/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
@@ -15,6 +15,13 @@
 #include "panfrost_gem.h"
 #include "panfrost_mmu.h"
 
+static bool panfrost_gem_shmem_is_purgeable(struct drm_gem_shmem_object *shmem)
+{
+	return (shmem->madv > 0) &&
+		!kref_read(&shmem->pages_pin_count) && shmem->sgt &&
+		!shmem->base.dma_buf && !shmem->base.import_attach;
+}
+
 static unsigned long
 panfrost_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc)
 {
@@ -27,7 +34,7 @@ panfrost_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc
 		return 0;
 
 	list_for_each_entry(shmem, &pfdev->shrinker_list, madv_list) {
-		if (drm_gem_shmem_is_purgeable(shmem))
+		if (panfrost_gem_shmem_is_purgeable(shmem))
 			count += shmem->base.size >> PAGE_SHIFT;
 	}
 
diff --git a/include/drm/drm_device.h b/include/drm/drm_device.h
index 7cf4afae2e79..a978f0cb5e84 100644
--- a/include/drm/drm_device.h
+++ b/include/drm/drm_device.h
@@ -16,6 +16,7 @@ struct drm_vblank_crtc;
 struct drm_vma_offset_manager;
 struct drm_vram_mm;
 struct drm_fb_helper;
+struct drm_gem_shmem_shrinker;
 
 struct inode;
 
@@ -290,8 +291,13 @@ struct drm_device {
 	/** @vma_offset_manager: GEM information */
 	struct drm_vma_offset_manager *vma_offset_manager;
 
-	/** @vram_mm: VRAM MM memory manager */
-	struct drm_vram_mm *vram_mm;
+	union {
+		/** @vram_mm: VRAM MM memory manager */
+		struct drm_vram_mm *vram_mm;
+
+		/** @shmem_mm: SHMEM GEM memory manager */
+		struct drm_gem_shmem *shmem_mm;
+	};
 
 	/**
 	 * @switch_power_state:
diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h
index 0e0ccd380f66..112dbe5208c0 100644
--- a/include/drm/drm_gem_shmem_helper.h
+++ b/include/drm/drm_gem_shmem_helper.h
@@ -6,6 +6,7 @@
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/mutex.h>
+#include <linux/shrinker.h>
 
 #include <drm/drm_file.h>
 #include <drm/drm_gem.h>
@@ -13,6 +14,7 @@
 #include <drm/drm_prime.h>
 
 struct dma_buf_attachment;
+struct drm_device;
 struct drm_mode_create_dumb;
 struct drm_printer;
 struct sg_table;
@@ -53,8 +55,8 @@ struct drm_gem_shmem_object {
 	 * @madv: State for madvise
 	 *
 	 * 0 is active/inuse.
+	 * 1 is not-needed/can-be-purged
 	 * A negative value is the object is purged.
-	 * Positive values are driver specific and not used by the helpers.
 	 */
 	int madv;
 
@@ -115,6 +117,12 @@ struct drm_gem_shmem_object {
 	 * @map_wc: map object write-combined (instead of using shmem defaults).
 	 */
 	bool map_wc : 1;
+
+	/**
+	 * @evicted: True if shmem pages are evicted by the memory shrinker.
+	 * Used internally by memory shrinker.
+	 */
+	bool evicted : 1;
 };
 
 #define to_drm_gem_shmem_obj(obj) \
@@ -133,14 +141,22 @@ void drm_gem_shmem_vunmap_locked(struct drm_gem_shmem_object *shmem,
 int drm_gem_shmem_mmap(struct drm_gem_shmem_object *shmem, struct vm_area_struct *vma);
 
 int drm_gem_shmem_madvise_locked(struct drm_gem_shmem_object *shmem, int madv);
+int drm_gem_shmem_madvise(struct drm_gem_shmem_object *shmem, int madv);
 
 static inline bool drm_gem_shmem_is_purgeable(struct drm_gem_shmem_object *shmem)
 {
-	return (shmem->madv > 0) &&
-		!kref_read(&shmem->pages_pin_count) && shmem->sgt &&
-		!shmem->base.dma_buf && !shmem->base.import_attach;
+	dma_resv_assert_held(shmem->base.resv);
+
+	return (shmem->madv > 0) && shmem->base.funcs->evict &&
+		kref_read(&shmem->pages_use_count) &&
+		!kref_read(&shmem->pages_pin_count) &&
+		!shmem->base.dma_buf && !shmem->base.import_attach &&
+		(shmem->sgt || shmem->evicted);
 }
 
+int drm_gem_shmem_swapin_locked(struct drm_gem_shmem_object *shmem);
+
+void drm_gem_shmem_evict_locked(struct drm_gem_shmem_object *shmem);
 void drm_gem_shmem_purge_locked(struct drm_gem_shmem_object *shmem);
 
 struct sg_table *drm_gem_shmem_get_sg_table(struct drm_gem_shmem_object *shmem);
@@ -284,6 +300,53 @@ static inline int drm_gem_shmem_object_mmap(struct drm_gem_object *obj, struct v
 	return drm_gem_shmem_mmap(shmem, vma);
 }
 
+/**
+ * drm_gem_shmem_object_madvise - unlocked GEM object function for drm_gem_shmem_madvise_locked()
+ * @obj: GEM object
+ * @madv: Madvise value
+ *
+ * This function wraps drm_gem_shmem_madvise_locked(), providing unlocked variant.
+ *
+ * Returns:
+ * 0 on success or a negative error code on failure.
+ */
+static inline int drm_gem_shmem_object_madvise(struct drm_gem_object *obj, int madv)
+{
+	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
+
+	return drm_gem_shmem_madvise(shmem, madv);
+}
+
+/**
+ * struct drm_gem_shmem_shrinker - Memory shrinker of GEM shmem memory manager
+ */
+struct drm_gem_shmem_shrinker {
+	/** @base: Shrinker for purging shmem GEM objects */
+	struct shrinker base;
+
+	/** @lock: Protects @lru_* */
+	struct mutex lock;
+
+	/** @lru_pinned: List of pinned shmem GEM objects */
+	struct drm_gem_lru lru_pinned;
+
+	/** @lru_evictable: List of shmem GEM objects to be evicted */
+	struct drm_gem_lru lru_evictable;
+
+	/** @lru_evicted: List of evicted shmem GEM objects */
+	struct drm_gem_lru lru_evicted;
+};
+
+/**
+ * struct drm_gem_shmem - GEM shmem memory manager
+ */
+struct drm_gem_shmem {
+	/** @shrinker: GEM shmem shrinker */
+	struct drm_gem_shmem_shrinker shrinker;
+};
+
+int drmm_gem_shmem_init(struct drm_device *dev);
+
 /*
  * Driver ops
  */
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v15 19/23] drm/shmem-helper: Export drm_gem_shmem_get_pages_sgt_locked()
  2023-08-27 17:54 [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Dmitry Osipenko
                   ` (17 preceding siblings ...)
  2023-08-27 17:54 ` [PATCH v15 18/23] drm/shmem-helper: Add memory shrinker Dmitry Osipenko
@ 2023-08-27 17:54 ` Dmitry Osipenko
  2023-08-27 17:54 ` [PATCH v15 20/23] drm/virtio: Pin display framebuffer BO Dmitry Osipenko
                   ` (4 subsequent siblings)
  23 siblings, 0 replies; 53+ messages in thread
From: Dmitry Osipenko @ 2023-08-27 17:54 UTC (permalink / raw)
  To: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Boris Brezillon, Emma Anholt, Melissa Wen, Will Deacon,
	Peter Zijlstra, Boqun Feng, Mark Rutland
  Cc: dri-devel, linux-kernel, kernel, virtualization, intel-gfx

Export drm_gem_shmem_get_pages_sgt_locked() that will be used by virtio-gpu
shrinker during GEM swap-in operation done under the held reservation lock.

Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
---
 drivers/gpu/drm/drm_gem_shmem_helper.c | 3 ++-
 include/drm/drm_gem_shmem_helper.h     | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
index f0f708e0ff00..62958af90383 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -888,7 +888,7 @@ struct sg_table *drm_gem_shmem_get_sg_table(struct drm_gem_shmem_object *shmem)
 }
 EXPORT_SYMBOL_GPL(drm_gem_shmem_get_sg_table);
 
-static struct sg_table *drm_gem_shmem_get_pages_sgt_locked(struct drm_gem_shmem_object *shmem)
+struct sg_table *drm_gem_shmem_get_pages_sgt_locked(struct drm_gem_shmem_object *shmem)
 {
 	struct drm_gem_object *obj = &shmem->base;
 	int ret;
@@ -927,6 +927,7 @@ static struct sg_table *drm_gem_shmem_get_pages_sgt_locked(struct drm_gem_shmem_
 	drm_gem_shmem_put_pages_locked(shmem);
 	return ERR_PTR(ret);
 }
+EXPORT_SYMBOL_GPL(drm_gem_shmem_get_pages_sgt_locked);
 
 /**
  * drm_gem_shmem_get_pages_sgt - Pin pages, dma map them, and return a
diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h
index 112dbe5208c0..e10ba533f74d 100644
--- a/include/drm/drm_gem_shmem_helper.h
+++ b/include/drm/drm_gem_shmem_helper.h
@@ -161,6 +161,7 @@ void drm_gem_shmem_purge_locked(struct drm_gem_shmem_object *shmem);
 
 struct sg_table *drm_gem_shmem_get_sg_table(struct drm_gem_shmem_object *shmem);
 struct sg_table *drm_gem_shmem_get_pages_sgt(struct drm_gem_shmem_object *shmem);
+struct sg_table *drm_gem_shmem_get_pages_sgt_locked(struct drm_gem_shmem_object *shmem);
 
 void drm_gem_shmem_print_info(const struct drm_gem_shmem_object *shmem,
 			      struct drm_printer *p, unsigned int indent);
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v15 20/23] drm/virtio: Pin display framebuffer BO
  2023-08-27 17:54 [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Dmitry Osipenko
                   ` (18 preceding siblings ...)
  2023-08-27 17:54 ` [PATCH v15 19/23] drm/shmem-helper: Export drm_gem_shmem_get_pages_sgt_locked() Dmitry Osipenko
@ 2023-08-27 17:54 ` Dmitry Osipenko
  2023-08-27 17:54 ` [PATCH v15 21/23] drm/virtio: Attach shmem BOs dynamically Dmitry Osipenko
                   ` (3 subsequent siblings)
  23 siblings, 0 replies; 53+ messages in thread
From: Dmitry Osipenko @ 2023-08-27 17:54 UTC (permalink / raw)
  To: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Boris Brezillon, Emma Anholt, Melissa Wen, Will Deacon,
	Peter Zijlstra, Boqun Feng, Mark Rutland
  Cc: dri-devel, linux-kernel, kernel, virtualization, intel-gfx

Prepare to addition of memory shrinker support by pinning display
framebuffer BO pages in memory while they are in use by display on host.
Shrinker is free to relocate framebuffer BO pages if it doesn't know that
pages are in use, thus pin the pages to disallow shrinker to move them.

Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
---
 drivers/gpu/drm/virtio/virtgpu_drv.h   |  2 ++
 drivers/gpu/drm/virtio/virtgpu_gem.c   | 19 +++++++++++++++++++
 drivers/gpu/drm/virtio/virtgpu_plane.c | 17 +++++++++++++++--
 3 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h
index 4126c384286b..5a4b74b7b318 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drv.h
+++ b/drivers/gpu/drm/virtio/virtgpu_drv.h
@@ -313,6 +313,8 @@ void virtio_gpu_array_put_free(struct virtio_gpu_object_array *objs);
 void virtio_gpu_array_put_free_delayed(struct virtio_gpu_device *vgdev,
 				       struct virtio_gpu_object_array *objs);
 void virtio_gpu_array_put_free_work(struct work_struct *work);
+int virtio_gpu_gem_pin(struct virtio_gpu_object *bo);
+void virtio_gpu_gem_unpin(struct virtio_gpu_object *bo);
 
 /* virtgpu_vq.c */
 int virtio_gpu_alloc_vbufs(struct virtio_gpu_device *vgdev);
diff --git a/drivers/gpu/drm/virtio/virtgpu_gem.c b/drivers/gpu/drm/virtio/virtgpu_gem.c
index 7db48d17ee3a..625c05d625bf 100644
--- a/drivers/gpu/drm/virtio/virtgpu_gem.c
+++ b/drivers/gpu/drm/virtio/virtgpu_gem.c
@@ -294,3 +294,22 @@ void virtio_gpu_array_put_free_work(struct work_struct *work)
 	}
 	spin_unlock(&vgdev->obj_free_lock);
 }
+
+int virtio_gpu_gem_pin(struct virtio_gpu_object *bo)
+{
+	int err;
+
+	if (virtio_gpu_is_shmem(bo)) {
+		err = drm_gem_shmem_pin(&bo->base);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+void virtio_gpu_gem_unpin(struct virtio_gpu_object *bo)
+{
+	if (virtio_gpu_is_shmem(bo))
+		drm_gem_shmem_unpin(&bo->base);
+}
diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c
index a2e045f3a000..def57b01a826 100644
--- a/drivers/gpu/drm/virtio/virtgpu_plane.c
+++ b/drivers/gpu/drm/virtio/virtgpu_plane.c
@@ -238,20 +238,28 @@ static int virtio_gpu_plane_prepare_fb(struct drm_plane *plane,
 	struct virtio_gpu_device *vgdev = dev->dev_private;
 	struct virtio_gpu_framebuffer *vgfb;
 	struct virtio_gpu_object *bo;
+	int err;
 
 	if (!new_state->fb)
 		return 0;
 
 	vgfb = to_virtio_gpu_framebuffer(new_state->fb);
 	bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]);
-	if (!bo || (plane->type == DRM_PLANE_TYPE_PRIMARY && !bo->guest_blob))
+
+	err = virtio_gpu_gem_pin(bo);
+	if (err)
+		return err;
+
+	if (plane->type == DRM_PLANE_TYPE_PRIMARY && !bo->guest_blob)
 		return 0;
 
 	if (bo->dumb && (plane->state->fb != new_state->fb)) {
 		vgfb->fence = virtio_gpu_fence_alloc(vgdev, vgdev->fence_drv.context,
 						     0);
-		if (!vgfb->fence)
+		if (!vgfb->fence) {
+			virtio_gpu_gem_unpin(bo);
 			return -ENOMEM;
+		}
 	}
 
 	return 0;
@@ -261,15 +269,20 @@ static void virtio_gpu_plane_cleanup_fb(struct drm_plane *plane,
 					struct drm_plane_state *state)
 {
 	struct virtio_gpu_framebuffer *vgfb;
+	struct virtio_gpu_object *bo;
 
 	if (!state->fb)
 		return;
 
 	vgfb = to_virtio_gpu_framebuffer(state->fb);
+	bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]);
+
 	if (vgfb->fence) {
 		dma_fence_put(&vgfb->fence->f);
 		vgfb->fence = NULL;
 	}
+
+	virtio_gpu_gem_unpin(bo);
 }
 
 static void virtio_gpu_cursor_plane_update(struct drm_plane *plane,
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v15 21/23] drm/virtio: Attach shmem BOs dynamically
  2023-08-27 17:54 [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Dmitry Osipenko
                   ` (19 preceding siblings ...)
  2023-08-27 17:54 ` [PATCH v15 20/23] drm/virtio: Pin display framebuffer BO Dmitry Osipenko
@ 2023-08-27 17:54 ` Dmitry Osipenko
  2023-08-27 17:54 ` [PATCH v15 22/23] drm/virtio: Support memory shrinking Dmitry Osipenko
                   ` (2 subsequent siblings)
  23 siblings, 0 replies; 53+ messages in thread
From: Dmitry Osipenko @ 2023-08-27 17:54 UTC (permalink / raw)
  To: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Boris Brezillon, Emma Anholt, Melissa Wen, Will Deacon,
	Peter Zijlstra, Boqun Feng, Mark Rutland
  Cc: dri-devel, linux-kernel, kernel, virtualization, intel-gfx

Prepare for addition of memory shrinker support by attaching shmem pages
to host dynamically on first use. The attachment vq command wasn't fenced
and there was no vq kick made in the BO creation code path, hence the
the attachment already was happening dynamically, but implicitly. Making
attachment explicitly dynamic will allow to simplify and reuse more code
when shrinker will be added. The virtio_gpu_object_shmem_init() now works
under held reservation lock, which will be important to have for shrinker.

Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
---
 drivers/gpu/drm/virtio/virtgpu_drv.h    |  7 +++
 drivers/gpu/drm/virtio/virtgpu_gem.c    | 26 ++++++++
 drivers/gpu/drm/virtio/virtgpu_ioctl.c  | 32 ++++++----
 drivers/gpu/drm/virtio/virtgpu_object.c | 80 ++++++++++++++++++++-----
 drivers/gpu/drm/virtio/virtgpu_submit.c | 15 ++++-
 5 files changed, 132 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h
index 5a4b74b7b318..8c82530eae82 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drv.h
+++ b/drivers/gpu/drm/virtio/virtgpu_drv.h
@@ -89,6 +89,7 @@ struct virtio_gpu_object {
 	uint32_t hw_res_handle;
 	bool dumb;
 	bool created;
+	bool detached;
 	bool host3d_blob, guest_blob;
 	uint32_t blob_mem, blob_flags;
 
@@ -313,6 +314,8 @@ void virtio_gpu_array_put_free(struct virtio_gpu_object_array *objs);
 void virtio_gpu_array_put_free_delayed(struct virtio_gpu_device *vgdev,
 				       struct virtio_gpu_object_array *objs);
 void virtio_gpu_array_put_free_work(struct work_struct *work);
+int virtio_gpu_array_prepare(struct virtio_gpu_device *vgdev,
+			     struct virtio_gpu_object_array *objs);
 int virtio_gpu_gem_pin(struct virtio_gpu_object *bo);
 void virtio_gpu_gem_unpin(struct virtio_gpu_object *bo);
 
@@ -458,6 +461,10 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev,
 
 bool virtio_gpu_is_shmem(struct virtio_gpu_object *bo);
 
+int virtio_gpu_reattach_shmem_object_locked(struct virtio_gpu_object *bo);
+
+int virtio_gpu_reattach_shmem_object(struct virtio_gpu_object *bo);
+
 int virtio_gpu_resource_id_get(struct virtio_gpu_device *vgdev,
 			       uint32_t *resid);
 /* virtgpu_prime.c */
diff --git a/drivers/gpu/drm/virtio/virtgpu_gem.c b/drivers/gpu/drm/virtio/virtgpu_gem.c
index 625c05d625bf..97e67064c97e 100644
--- a/drivers/gpu/drm/virtio/virtgpu_gem.c
+++ b/drivers/gpu/drm/virtio/virtgpu_gem.c
@@ -295,6 +295,26 @@ void virtio_gpu_array_put_free_work(struct work_struct *work)
 	spin_unlock(&vgdev->obj_free_lock);
 }
 
+int virtio_gpu_array_prepare(struct virtio_gpu_device *vgdev,
+			     struct virtio_gpu_object_array *objs)
+{
+	struct virtio_gpu_object *bo;
+	int ret = 0;
+	u32 i;
+
+	for (i = 0; i < objs->nents; i++) {
+		bo = gem_to_virtio_gpu_obj(objs->objs[i]);
+
+		if (virtio_gpu_is_shmem(bo) && bo->detached) {
+			ret = virtio_gpu_reattach_shmem_object_locked(bo);
+			if (ret)
+				break;
+		}
+	}
+
+	return ret;
+}
+
 int virtio_gpu_gem_pin(struct virtio_gpu_object *bo)
 {
 	int err;
@@ -303,6 +323,12 @@ int virtio_gpu_gem_pin(struct virtio_gpu_object *bo)
 		err = drm_gem_shmem_pin(&bo->base);
 		if (err)
 			return err;
+
+		err = virtio_gpu_reattach_shmem_object(bo);
+		if (err) {
+			drm_gem_shmem_unpin(&bo->base);
+			return err;
+		}
 	}
 
 	return 0;
diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c
index b24b11f25197..070c29cea26a 100644
--- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c
+++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c
@@ -246,6 +246,10 @@ static int virtio_gpu_transfer_from_host_ioctl(struct drm_device *dev,
 	if (ret != 0)
 		goto err_put_free;
 
+	ret = virtio_gpu_array_prepare(vgdev, objs);
+	if (ret)
+		goto err_unlock;
+
 	fence = virtio_gpu_fence_alloc(vgdev, vgdev->fence_drv.context, 0);
 	if (!fence) {
 		ret = -ENOMEM;
@@ -288,11 +292,25 @@ static int virtio_gpu_transfer_to_host_ioctl(struct drm_device *dev, void *data,
 		goto err_put_free;
 	}
 
+	ret = virtio_gpu_array_lock_resv(objs);
+	if (ret != 0)
+		goto err_put_free;
+
+	ret = virtio_gpu_array_prepare(vgdev, objs);
+	if (ret)
+		goto err_unlock;
+
+	fence = virtio_gpu_fence_alloc(vgdev, vgdev->fence_drv.context, 0);
+	if (!fence) {
+		ret = -ENOMEM;
+		goto err_unlock;
+	}
+
 	if (!vgdev->has_virgl_3d) {
 		virtio_gpu_cmd_transfer_to_host_2d
 			(vgdev, offset,
 			 args->box.w, args->box.h, args->box.x, args->box.y,
-			 objs, NULL);
+			 objs, fence);
 	} else {
 		virtio_gpu_create_context(dev, file);
 
@@ -301,23 +319,13 @@ static int virtio_gpu_transfer_to_host_ioctl(struct drm_device *dev, void *data,
 			goto err_put_free;
 		}
 
-		ret = virtio_gpu_array_lock_resv(objs);
-		if (ret != 0)
-			goto err_put_free;
-
-		ret = -ENOMEM;
-		fence = virtio_gpu_fence_alloc(vgdev, vgdev->fence_drv.context,
-					       0);
-		if (!fence)
-			goto err_unlock;
-
 		virtio_gpu_cmd_transfer_to_host_3d
 			(vgdev,
 			 vfpriv ? vfpriv->ctx_id : 0, offset, args->level,
 			 args->stride, args->layer_stride, &args->box, objs,
 			 fence);
-		dma_fence_put(&fence->f);
 	}
+	dma_fence_put(&fence->f);
 	virtio_gpu_notify(vgdev);
 	return 0;
 
diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c b/drivers/gpu/drm/virtio/virtgpu_object.c
index 97020ed56b81..044b08aa78ac 100644
--- a/drivers/gpu/drm/virtio/virtgpu_object.c
+++ b/drivers/gpu/drm/virtio/virtgpu_object.c
@@ -142,10 +142,13 @@ static int virtio_gpu_object_shmem_init(struct virtio_gpu_device *vgdev,
 	struct sg_table *pages;
 	int si;
 
-	pages = drm_gem_shmem_get_pages_sgt(&bo->base);
+	pages = drm_gem_shmem_get_pages_sgt_locked(&bo->base);
 	if (IS_ERR(pages))
 		return PTR_ERR(pages);
 
+	if (!ents)
+		return 0;
+
 	if (use_dma_api)
 		*nents = pages->nents;
 	else
@@ -176,6 +179,40 @@ static int virtio_gpu_object_shmem_init(struct virtio_gpu_device *vgdev,
 	return 0;
 }
 
+int virtio_gpu_reattach_shmem_object_locked(struct virtio_gpu_object *bo)
+{
+	struct virtio_gpu_device *vgdev = bo->base.base.dev->dev_private;
+	struct virtio_gpu_mem_entry *ents;
+	unsigned int nents;
+	int err;
+
+	if (!bo->detached)
+		return 0;
+
+	err = virtio_gpu_object_shmem_init(vgdev, bo, &ents, &nents);
+	if (err)
+		return err;
+
+	virtio_gpu_object_attach(vgdev, bo, ents, nents);
+
+	bo->detached = false;
+
+	return 0;
+}
+
+int virtio_gpu_reattach_shmem_object(struct virtio_gpu_object *bo)
+{
+	int ret;
+
+	ret = dma_resv_lock_interruptible(bo->base.base.resv, NULL);
+	if (ret)
+		return ret;
+	ret = virtio_gpu_reattach_shmem_object_locked(bo);
+	dma_resv_unlock(bo->base.base.resv);
+
+	return ret;
+}
+
 int virtio_gpu_object_create(struct virtio_gpu_device *vgdev,
 			     struct virtio_gpu_object_params *params,
 			     struct virtio_gpu_object **bo_ptr,
@@ -202,45 +239,60 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev,
 
 	bo->dumb = params->dumb;
 
-	ret = virtio_gpu_object_shmem_init(vgdev, bo, &ents, &nents);
-	if (ret != 0)
-		goto err_put_id;
+	if (bo->blob_mem == VIRTGPU_BLOB_MEM_GUEST)
+		bo->guest_blob = true;
 
 	if (fence) {
 		ret = -ENOMEM;
 		objs = virtio_gpu_array_alloc(1);
 		if (!objs)
-			goto err_free_entry;
+			goto err_put_id;
 		virtio_gpu_array_add_obj(objs, &bo->base.base);
 
 		ret = virtio_gpu_array_lock_resv(objs);
 		if (ret != 0)
 			goto err_put_objs;
+	} else {
+		ret = dma_resv_lock(bo->base.base.resv, NULL);
+		if (ret)
+			goto err_put_id;
 	}
 
 	if (params->blob) {
-		if (params->blob_mem == VIRTGPU_BLOB_MEM_GUEST)
-			bo->guest_blob = true;
+		ret = virtio_gpu_object_shmem_init(vgdev, bo, &ents, &nents);
+		if (ret)
+			goto err_unlock_objs;
+	} else {
+		ret = virtio_gpu_object_shmem_init(vgdev, bo, NULL, NULL);
+		if (ret)
+			goto err_unlock_objs;
 
+		bo->detached = true;
+	}
+
+	if (params->blob)
 		virtio_gpu_cmd_resource_create_blob(vgdev, bo, params,
 						    ents, nents);
-	} else if (params->virgl) {
+	else if (params->virgl)
 		virtio_gpu_cmd_resource_create_3d(vgdev, bo, params,
 						  objs, fence);
-		virtio_gpu_object_attach(vgdev, bo, ents, nents);
-	} else {
+	else
 		virtio_gpu_cmd_create_resource(vgdev, bo, params,
 					       objs, fence);
-		virtio_gpu_object_attach(vgdev, bo, ents, nents);
-	}
+
+	if (!fence)
+		dma_resv_unlock(bo->base.base.resv);
 
 	*bo_ptr = bo;
 	return 0;
 
+err_unlock_objs:
+	if (fence)
+		virtio_gpu_array_unlock_resv(objs);
+	else
+		dma_resv_unlock(bo->base.base.resv);
 err_put_objs:
 	virtio_gpu_array_put_free(objs);
-err_free_entry:
-	kvfree(ents);
 err_put_id:
 	virtio_gpu_resource_id_put(vgdev, bo->hw_res_handle);
 err_free_gem:
diff --git a/drivers/gpu/drm/virtio/virtgpu_submit.c b/drivers/gpu/drm/virtio/virtgpu_submit.c
index 3c00135ead45..94867f485a64 100644
--- a/drivers/gpu/drm/virtio/virtgpu_submit.c
+++ b/drivers/gpu/drm/virtio/virtgpu_submit.c
@@ -465,8 +465,19 @@ static void virtio_gpu_install_out_fence_fd(struct virtio_gpu_submit *submit)
 
 static int virtio_gpu_lock_buflist(struct virtio_gpu_submit *submit)
 {
-	if (submit->buflist)
-		return virtio_gpu_array_lock_resv(submit->buflist);
+	int err;
+
+	if (submit->buflist) {
+		err = virtio_gpu_array_lock_resv(submit->buflist);
+		if (err)
+			return err;
+
+		err = virtio_gpu_array_prepare(submit->vgdev, submit->buflist);
+		if (err) {
+			virtio_gpu_array_unlock_resv(submit->buflist);
+			return err;
+		}
+	}
 
 	return 0;
 }
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v15 22/23] drm/virtio: Support memory shrinking
  2023-08-27 17:54 [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Dmitry Osipenko
                   ` (20 preceding siblings ...)
  2023-08-27 17:54 ` [PATCH v15 21/23] drm/virtio: Attach shmem BOs dynamically Dmitry Osipenko
@ 2023-08-27 17:54 ` Dmitry Osipenko
  2023-08-27 17:54 ` [PATCH v15 23/23] drm/panfrost: Switch to generic memory shrinker Dmitry Osipenko
  2023-08-28 14:37 ` [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Helen Mae Koike Fornazier
  23 siblings, 0 replies; 53+ messages in thread
From: Dmitry Osipenko @ 2023-08-27 17:54 UTC (permalink / raw)
  To: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Boris Brezillon, Emma Anholt, Melissa Wen, Will Deacon,
	Peter Zijlstra, Boqun Feng, Mark Rutland
  Cc: dri-devel, linux-kernel, kernel, virtualization, intel-gfx

Support generic drm-shmem memory shrinker and add new madvise IOCTL to
the VirtIO-GPU driver. BO cache manager of Mesa driver will mark BOs as
"don't need" using the new IOCTL to let shrinker purge the marked BOs on
OOM, the shrinker will also evict unpurgeable shmem BOs from memory if
guest supports SWAP file or partition.

Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
---
 drivers/gpu/drm/virtio/virtgpu_drv.h    | 13 +++++-
 drivers/gpu/drm/virtio/virtgpu_gem.c    | 35 ++++++++++++++
 drivers/gpu/drm/virtio/virtgpu_ioctl.c  | 25 ++++++++++
 drivers/gpu/drm/virtio/virtgpu_kms.c    |  8 ++++
 drivers/gpu/drm/virtio/virtgpu_object.c | 61 +++++++++++++++++++++++++
 drivers/gpu/drm/virtio/virtgpu_vq.c     | 40 ++++++++++++++++
 include/uapi/drm/virtgpu_drm.h          | 14 ++++++
 7 files changed, 195 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h
index 8c82530eae82..a34da2036221 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drv.h
+++ b/drivers/gpu/drm/virtio/virtgpu_drv.h
@@ -278,7 +278,7 @@ struct virtio_gpu_fpriv {
 };
 
 /* virtgpu_ioctl.c */
-#define DRM_VIRTIO_NUM_IOCTLS 12
+#define DRM_VIRTIO_NUM_IOCTLS 13
 extern struct drm_ioctl_desc virtio_gpu_ioctls[DRM_VIRTIO_NUM_IOCTLS];
 void virtio_gpu_create_context(struct drm_device *dev, struct drm_file *file);
 
@@ -316,6 +316,8 @@ void virtio_gpu_array_put_free_delayed(struct virtio_gpu_device *vgdev,
 void virtio_gpu_array_put_free_work(struct work_struct *work);
 int virtio_gpu_array_prepare(struct virtio_gpu_device *vgdev,
 			     struct virtio_gpu_object_array *objs);
+int virtio_gpu_gem_host_mem_release(struct virtio_gpu_object *bo);
+int virtio_gpu_gem_madvise(struct virtio_gpu_object *obj, int madv);
 int virtio_gpu_gem_pin(struct virtio_gpu_object *bo);
 void virtio_gpu_gem_unpin(struct virtio_gpu_object *bo);
 
@@ -329,6 +331,8 @@ void virtio_gpu_cmd_create_resource(struct virtio_gpu_device *vgdev,
 				    struct virtio_gpu_fence *fence);
 void virtio_gpu_cmd_unref_resource(struct virtio_gpu_device *vgdev,
 				   struct virtio_gpu_object *bo);
+int virtio_gpu_cmd_release_resource(struct virtio_gpu_device *vgdev,
+				    struct virtio_gpu_object *bo);
 void virtio_gpu_cmd_transfer_to_host_2d(struct virtio_gpu_device *vgdev,
 					uint64_t offset,
 					uint32_t width, uint32_t height,
@@ -349,6 +353,9 @@ void virtio_gpu_object_attach(struct virtio_gpu_device *vgdev,
 			      struct virtio_gpu_object *obj,
 			      struct virtio_gpu_mem_entry *ents,
 			      unsigned int nents);
+void virtio_gpu_object_detach(struct virtio_gpu_device *vgdev,
+			      struct virtio_gpu_object *obj,
+			      struct virtio_gpu_fence *fence);
 int virtio_gpu_attach_status_page(struct virtio_gpu_device *vgdev);
 int virtio_gpu_detach_status_page(struct virtio_gpu_device *vgdev);
 void virtio_gpu_cursor_ping(struct virtio_gpu_device *vgdev,
@@ -499,4 +506,8 @@ void virtio_gpu_vram_unmap_dma_buf(struct device *dev,
 int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data,
 				struct drm_file *file);
 
+/* virtgpu_gem_shrinker.c */
+int virtio_gpu_gem_shrinker_init(struct virtio_gpu_device *vgdev);
+void virtio_gpu_gem_shrinker_fini(struct virtio_gpu_device *vgdev);
+
 #endif
diff --git a/drivers/gpu/drm/virtio/virtgpu_gem.c b/drivers/gpu/drm/virtio/virtgpu_gem.c
index 97e67064c97e..748f7bbb0e6d 100644
--- a/drivers/gpu/drm/virtio/virtgpu_gem.c
+++ b/drivers/gpu/drm/virtio/virtgpu_gem.c
@@ -147,10 +147,20 @@ void virtio_gpu_gem_object_close(struct drm_gem_object *obj,
 	struct virtio_gpu_device *vgdev = obj->dev->dev_private;
 	struct virtio_gpu_fpriv *vfpriv = file->driver_priv;
 	struct virtio_gpu_object_array *objs;
+	struct virtio_gpu_object *bo;
 
 	if (!vgdev->has_virgl_3d)
 		return;
 
+	bo = gem_to_virtio_gpu_obj(obj);
+
+	/*
+	 * Purged BO was already detached and released, the resource ID
+	 * is invalid by now.
+	 */
+	if (!virtio_gpu_gem_madvise(bo, VIRTGPU_MADV_WILLNEED))
+		return;
+
 	objs = virtio_gpu_array_alloc(1);
 	if (!objs)
 		return;
@@ -315,6 +325,31 @@ int virtio_gpu_array_prepare(struct virtio_gpu_device *vgdev,
 	return ret;
 }
 
+int virtio_gpu_gem_madvise(struct virtio_gpu_object *bo, int madv)
+{
+	if (virtio_gpu_is_shmem(bo))
+		return drm_gem_shmem_object_madvise(&bo->base.base, madv);
+
+	return 1;
+}
+
+int virtio_gpu_gem_host_mem_release(struct virtio_gpu_object *bo)
+{
+	struct virtio_gpu_device *vgdev = bo->base.base.dev->dev_private;
+	int err;
+
+	if (bo->created) {
+		err = virtio_gpu_cmd_release_resource(vgdev, bo);
+		if (err)
+			return err;
+
+		virtio_gpu_notify(vgdev);
+		bo->created = false;
+	}
+
+	return 0;
+}
+
 int virtio_gpu_gem_pin(struct virtio_gpu_object *bo)
 {
 	int err;
diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c
index 070c29cea26a..44a99166efdc 100644
--- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c
+++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c
@@ -676,6 +676,28 @@ static int virtio_gpu_context_init_ioctl(struct drm_device *dev,
 	return ret;
 }
 
+static int virtio_gpu_madvise_ioctl(struct drm_device *dev,
+				    void *data,
+				    struct drm_file *file)
+{
+	struct drm_virtgpu_madvise *args = data;
+	struct virtio_gpu_object *bo;
+	struct drm_gem_object *obj;
+
+	if (args->madv > VIRTGPU_MADV_DONTNEED)
+		return -EOPNOTSUPP;
+
+	obj = drm_gem_object_lookup(file, args->bo_handle);
+	if (!obj)
+		return -ENOENT;
+
+	bo = gem_to_virtio_gpu_obj(obj);
+	args->retained = virtio_gpu_gem_madvise(bo, args->madv);
+	drm_gem_object_put(obj);
+
+	return 0;
+}
+
 struct drm_ioctl_desc virtio_gpu_ioctls[DRM_VIRTIO_NUM_IOCTLS] = {
 	DRM_IOCTL_DEF_DRV(VIRTGPU_MAP, virtio_gpu_map_ioctl,
 			  DRM_RENDER_ALLOW),
@@ -715,4 +737,7 @@ struct drm_ioctl_desc virtio_gpu_ioctls[DRM_VIRTIO_NUM_IOCTLS] = {
 
 	DRM_IOCTL_DEF_DRV(VIRTGPU_CONTEXT_INIT, virtio_gpu_context_init_ioctl,
 			  DRM_RENDER_ALLOW),
+
+	DRM_IOCTL_DEF_DRV(VIRTGPU_MADVISE, virtio_gpu_madvise_ioctl,
+			  DRM_RENDER_ALLOW),
 };
diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c
index 5a3b5aaed1f3..43e237082cec 100644
--- a/drivers/gpu/drm/virtio/virtgpu_kms.c
+++ b/drivers/gpu/drm/virtio/virtgpu_kms.c
@@ -245,6 +245,12 @@ int virtio_gpu_init(struct virtio_device *vdev, struct drm_device *dev)
 		goto err_scanouts;
 	}
 
+	ret = drmm_gem_shmem_init(dev);
+	if (ret) {
+		DRM_ERROR("shmem init failed\n");
+		goto err_modeset;
+	}
+
 	virtio_device_ready(vgdev->vdev);
 
 	if (num_capsets)
@@ -259,6 +265,8 @@ int virtio_gpu_init(struct virtio_device *vdev, struct drm_device *dev)
 	}
 	return 0;
 
+err_modeset:
+	virtio_gpu_modeset_fini(vgdev);
 err_scanouts:
 	virtio_gpu_free_vbufs(vgdev);
 err_vbufs:
diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c b/drivers/gpu/drm/virtio/virtgpu_object.c
index 044b08aa78ac..dc4df8f2d89c 100644
--- a/drivers/gpu/drm/virtio/virtgpu_object.c
+++ b/drivers/gpu/drm/virtio/virtgpu_object.c
@@ -97,6 +97,60 @@ static void virtio_gpu_free_object(struct drm_gem_object *obj)
 	virtio_gpu_cleanup_object(bo);
 }
 
+static int virtio_gpu_detach_object_fenced(struct virtio_gpu_object *bo)
+{
+	struct virtio_gpu_device *vgdev = bo->base.base.dev->dev_private;
+	struct virtio_gpu_fence *fence;
+
+	if (bo->detached)
+		return 0;
+
+	fence = virtio_gpu_fence_alloc(vgdev, vgdev->fence_drv.context, 0);
+	if (!fence)
+		return -ENOMEM;
+
+	virtio_gpu_object_detach(vgdev, bo, fence);
+	virtio_gpu_notify(vgdev);
+
+	dma_fence_wait(&fence->f, false);
+	dma_fence_put(&fence->f);
+
+	bo->detached = true;
+
+	return 0;
+}
+
+static int virtio_gpu_shmem_evict(struct drm_gem_object *obj)
+{
+	struct virtio_gpu_object *bo = gem_to_virtio_gpu_obj(obj);
+	int err;
+
+	/* blob is not movable, it's impossible to detach it from host */
+	if (bo->blob_mem)
+		return -EBUSY;
+
+	/*
+	 * At first tell host to stop using guest's memory to ensure that
+	 * host won't touch the released guest's memory once it's gone.
+	 */
+	err = virtio_gpu_detach_object_fenced(bo);
+	if (err)
+		return err;
+
+	if (drm_gem_shmem_is_purgeable(&bo->base)) {
+		err = virtio_gpu_gem_host_mem_release(bo);
+		if (err)
+			return err;
+
+		drm_gem_shmem_purge_locked(&bo->base);
+	} else {
+		bo->base.pages_mark_dirty_on_put = 1;
+		drm_gem_shmem_evict_locked(&bo->base);
+	}
+
+	return 0;
+}
+
 static const struct drm_gem_object_funcs virtio_gpu_shmem_funcs = {
 	.free = virtio_gpu_free_object,
 	.open = virtio_gpu_gem_object_open,
@@ -110,6 +164,7 @@ static const struct drm_gem_object_funcs virtio_gpu_shmem_funcs = {
 	.vunmap = drm_gem_shmem_object_vunmap_locked,
 	.mmap = drm_gem_shmem_object_mmap,
 	.vm_ops = &drm_gem_shmem_vm_ops,
+	.evict = virtio_gpu_shmem_evict,
 };
 
 bool virtio_gpu_is_shmem(struct virtio_gpu_object *bo)
@@ -189,6 +244,10 @@ int virtio_gpu_reattach_shmem_object_locked(struct virtio_gpu_object *bo)
 	if (!bo->detached)
 		return 0;
 
+	err = drm_gem_shmem_swapin_locked(&bo->base);
+	if (err)
+		return err;
+
 	err = virtio_gpu_object_shmem_init(vgdev, bo, &ents, &nents);
 	if (err)
 		return err;
@@ -238,6 +297,8 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev,
 		goto err_free_gem;
 
 	bo->dumb = params->dumb;
+	bo->blob_mem = params->blob_mem;
+	bo->blob_flags = params->blob_flags;
 
 	if (bo->blob_mem == VIRTGPU_BLOB_MEM_GUEST)
 		bo->guest_blob = true;
diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c
index b1a00c0c25a7..14ab470f413a 100644
--- a/drivers/gpu/drm/virtio/virtgpu_vq.c
+++ b/drivers/gpu/drm/virtio/virtgpu_vq.c
@@ -545,6 +545,21 @@ void virtio_gpu_cmd_unref_resource(struct virtio_gpu_device *vgdev,
 		virtio_gpu_cleanup_object(bo);
 }
 
+int virtio_gpu_cmd_release_resource(struct virtio_gpu_device *vgdev,
+				    struct virtio_gpu_object *bo)
+{
+	struct virtio_gpu_resource_unref *cmd_p;
+	struct virtio_gpu_vbuffer *vbuf;
+
+	cmd_p = virtio_gpu_alloc_cmd(vgdev, &vbuf, sizeof(*cmd_p));
+	memset(cmd_p, 0, sizeof(*cmd_p));
+
+	cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_UNREF);
+	cmd_p->resource_id = cpu_to_le32(bo->hw_res_handle);
+
+	return virtio_gpu_queue_ctrl_buffer(vgdev, vbuf);
+}
+
 void virtio_gpu_cmd_set_scanout(struct virtio_gpu_device *vgdev,
 				uint32_t scanout_id, uint32_t resource_id,
 				uint32_t width, uint32_t height,
@@ -645,6 +660,23 @@ virtio_gpu_cmd_resource_attach_backing(struct virtio_gpu_device *vgdev,
 	virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, fence);
 }
 
+static void
+virtio_gpu_cmd_resource_detach_backing(struct virtio_gpu_device *vgdev,
+				       u32 resource_id,
+				       struct virtio_gpu_fence *fence)
+{
+	struct virtio_gpu_resource_attach_backing *cmd_p;
+	struct virtio_gpu_vbuffer *vbuf;
+
+	cmd_p = virtio_gpu_alloc_cmd(vgdev, &vbuf, sizeof(*cmd_p));
+	memset(cmd_p, 0, sizeof(*cmd_p));
+
+	cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING);
+	cmd_p->resource_id = cpu_to_le32(resource_id);
+
+	virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, fence);
+}
+
 static void virtio_gpu_cmd_get_display_info_cb(struct virtio_gpu_device *vgdev,
 					       struct virtio_gpu_vbuffer *vbuf)
 {
@@ -1107,6 +1139,14 @@ void virtio_gpu_object_attach(struct virtio_gpu_device *vgdev,
 					       ents, nents, NULL);
 }
 
+void virtio_gpu_object_detach(struct virtio_gpu_device *vgdev,
+			      struct virtio_gpu_object *obj,
+			      struct virtio_gpu_fence *fence)
+{
+	virtio_gpu_cmd_resource_detach_backing(vgdev, obj->hw_res_handle,
+					       fence);
+}
+
 void virtio_gpu_cursor_ping(struct virtio_gpu_device *vgdev,
 			    struct virtio_gpu_output *output)
 {
diff --git a/include/uapi/drm/virtgpu_drm.h b/include/uapi/drm/virtgpu_drm.h
index b1d0e56565bc..4caba71b2740 100644
--- a/include/uapi/drm/virtgpu_drm.h
+++ b/include/uapi/drm/virtgpu_drm.h
@@ -48,6 +48,7 @@ extern "C" {
 #define DRM_VIRTGPU_GET_CAPS  0x09
 #define DRM_VIRTGPU_RESOURCE_CREATE_BLOB 0x0a
 #define DRM_VIRTGPU_CONTEXT_INIT 0x0b
+#define DRM_VIRTGPU_MADVISE 0x0c
 
 #define VIRTGPU_EXECBUF_FENCE_FD_IN	0x01
 #define VIRTGPU_EXECBUF_FENCE_FD_OUT	0x02
@@ -211,6 +212,15 @@ struct drm_virtgpu_context_init {
 	__u64 ctx_set_params;
 };
 
+#define VIRTGPU_MADV_WILLNEED 0
+#define VIRTGPU_MADV_DONTNEED 1
+struct drm_virtgpu_madvise {
+	__u32 bo_handle;
+	__u32 retained; /* out, non-zero if BO can be used */
+	__u32 madv;
+	__u32 pad;
+};
+
 /*
  * Event code that's given when VIRTGPU_CONTEXT_PARAM_POLL_RINGS_MASK is in
  * effect.  The event size is sizeof(drm_event), since there is no additional
@@ -261,6 +271,10 @@ struct drm_virtgpu_context_init {
 	DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_CONTEXT_INIT,		\
 		struct drm_virtgpu_context_init)
 
+#define DRM_IOCTL_VIRTGPU_MADVISE \
+	DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_MADVISE, \
+		 struct drm_virtgpu_madvise)
+
 #if defined(__cplusplus)
 }
 #endif
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH v15 23/23] drm/panfrost: Switch to generic memory shrinker
  2023-08-27 17:54 [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Dmitry Osipenko
                   ` (21 preceding siblings ...)
  2023-08-27 17:54 ` [PATCH v15 22/23] drm/virtio: Support memory shrinking Dmitry Osipenko
@ 2023-08-27 17:54 ` Dmitry Osipenko
  2023-08-28 14:37 ` [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Helen Mae Koike Fornazier
  23 siblings, 0 replies; 53+ messages in thread
From: Dmitry Osipenko @ 2023-08-27 17:54 UTC (permalink / raw)
  To: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Boris Brezillon, Emma Anholt, Melissa Wen, Will Deacon,
	Peter Zijlstra, Boqun Feng, Mark Rutland
  Cc: dri-devel, linux-kernel, kernel, virtualization, intel-gfx

Replace Panfrost's custom memory shrinker with a common drm-shmem
memory shrinker.

Tested-by: Steven Price <steven.price@arm.com> # Firefly-RK3288
Reviewed-by: Steven Price <steven.price@arm.com>
Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
---
 drivers/gpu/drm/panfrost/Makefile             |   1 -
 drivers/gpu/drm/panfrost/panfrost_device.h    |   4 -
 drivers/gpu/drm/panfrost/panfrost_drv.c       |  27 ++--
 drivers/gpu/drm/panfrost/panfrost_gem.c       |  30 ++--
 drivers/gpu/drm/panfrost/panfrost_gem.h       |   9 --
 .../gpu/drm/panfrost/panfrost_gem_shrinker.c  | 129 ------------------
 drivers/gpu/drm/panfrost/panfrost_job.c       |  18 ++-
 include/drm/drm_gem_shmem_helper.h            |   7 -
 8 files changed, 47 insertions(+), 178 deletions(-)
 delete mode 100644 drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c

diff --git a/drivers/gpu/drm/panfrost/Makefile b/drivers/gpu/drm/panfrost/Makefile
index 7da2b3f02ed9..11622e22cf15 100644
--- a/drivers/gpu/drm/panfrost/Makefile
+++ b/drivers/gpu/drm/panfrost/Makefile
@@ -5,7 +5,6 @@ panfrost-y := \
 	panfrost_device.o \
 	panfrost_devfreq.o \
 	panfrost_gem.o \
-	panfrost_gem_shrinker.o \
 	panfrost_gpu.o \
 	panfrost_job.o \
 	panfrost_mmu.o \
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h
index b0126b9fbadc..dcc2571c092b 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.h
+++ b/drivers/gpu/drm/panfrost/panfrost_device.h
@@ -116,10 +116,6 @@ struct panfrost_device {
 		atomic_t pending;
 	} reset;
 
-	struct mutex shrinker_lock;
-	struct list_head shrinker_list;
-	struct shrinker shrinker;
-
 	struct panfrost_devfreq pfdevfreq;
 };
 
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c
index 175443eacead..8cf338c2a03b 100644
--- a/drivers/gpu/drm/panfrost/panfrost_drv.c
+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
@@ -170,7 +170,6 @@ panfrost_lookup_bos(struct drm_device *dev,
 			break;
 		}
 
-		atomic_inc(&bo->gpu_usecount);
 		job->mappings[i] = mapping;
 	}
 
@@ -395,7 +394,6 @@ static int panfrost_ioctl_madvise(struct drm_device *dev, void *data,
 {
 	struct panfrost_file_priv *priv = file_priv->driver_priv;
 	struct drm_panfrost_madvise *args = data;
-	struct panfrost_device *pfdev = dev->dev_private;
 	struct drm_gem_object *gem_obj;
 	struct panfrost_gem_object *bo;
 	int ret = 0;
@@ -408,11 +406,15 @@ static int panfrost_ioctl_madvise(struct drm_device *dev, void *data,
 
 	bo = to_panfrost_bo(gem_obj);
 
+	if (bo->is_heap) {
+		args->retained = 1;
+		goto out_put_object;
+	}
+
 	ret = dma_resv_lock_interruptible(bo->base.base.resv, NULL);
 	if (ret)
 		goto out_put_object;
 
-	mutex_lock(&pfdev->shrinker_lock);
 	mutex_lock(&bo->mappings.lock);
 	if (args->madv == PANFROST_MADV_DONTNEED) {
 		struct panfrost_gem_mapping *first;
@@ -438,17 +440,8 @@ static int panfrost_ioctl_madvise(struct drm_device *dev, void *data,
 
 	args->retained = drm_gem_shmem_madvise_locked(&bo->base, args->madv);
 
-	if (args->retained) {
-		if (args->madv == PANFROST_MADV_DONTNEED)
-			list_move_tail(&bo->base.madv_list,
-				       &pfdev->shrinker_list);
-		else if (args->madv == PANFROST_MADV_WILLNEED)
-			list_del_init(&bo->base.madv_list);
-	}
-
 out_unlock_mappings:
 	mutex_unlock(&bo->mappings.lock);
-	mutex_unlock(&pfdev->shrinker_lock);
 	dma_resv_unlock(bo->base.base.resv);
 out_put_object:
 	drm_gem_object_put(gem_obj);
@@ -577,9 +570,6 @@ static int panfrost_probe(struct platform_device *pdev)
 	ddev->dev_private = pfdev;
 	pfdev->ddev = ddev;
 
-	mutex_init(&pfdev->shrinker_lock);
-	INIT_LIST_HEAD(&pfdev->shrinker_list);
-
 	err = panfrost_device_init(pfdev);
 	if (err) {
 		if (err != -EPROBE_DEFER)
@@ -601,10 +591,14 @@ static int panfrost_probe(struct platform_device *pdev)
 	if (err < 0)
 		goto err_out1;
 
-	panfrost_gem_shrinker_init(ddev);
+	err = drmm_gem_shmem_init(ddev);
+	if (err < 0)
+		goto err_out2;
 
 	return 0;
 
+err_out2:
+	drm_dev_unregister(ddev);
 err_out1:
 	pm_runtime_disable(pfdev->dev);
 	panfrost_device_fini(pfdev);
@@ -620,7 +614,6 @@ static void panfrost_remove(struct platform_device *pdev)
 	struct drm_device *ddev = pfdev->ddev;
 
 	drm_dev_unregister(ddev);
-	panfrost_gem_shrinker_cleanup(ddev);
 
 	pm_runtime_get_sync(pfdev->dev);
 	pm_runtime_disable(pfdev->dev);
diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.c b/drivers/gpu/drm/panfrost/panfrost_gem.c
index 59c8c73c6a59..00165fca7f3d 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gem.c
+++ b/drivers/gpu/drm/panfrost/panfrost_gem.c
@@ -19,16 +19,6 @@ static void panfrost_gem_free_object(struct drm_gem_object *obj)
 	struct panfrost_gem_object *bo = to_panfrost_bo(obj);
 	struct panfrost_device *pfdev = obj->dev->dev_private;
 
-	/*
-	 * Make sure the BO is no longer inserted in the shrinker list before
-	 * taking care of the destruction itself. If we don't do that we have a
-	 * race condition between this function and what's done in
-	 * panfrost_gem_shrinker_scan().
-	 */
-	mutex_lock(&pfdev->shrinker_lock);
-	list_del_init(&bo->base.madv_list);
-	mutex_unlock(&pfdev->shrinker_lock);
-
 	/*
 	 * If we still have mappings attached to the BO, there's a problem in
 	 * our refcounting.
@@ -195,6 +185,25 @@ static int panfrost_gem_pin(struct drm_gem_object *obj)
 	return drm_gem_shmem_object_pin(obj);
 }
 
+static int panfrost_shmem_evict(struct drm_gem_object *obj)
+{
+	struct panfrost_gem_object *bo = to_panfrost_bo(obj);
+
+	if (!drm_gem_shmem_is_purgeable(&bo->base))
+		return -EBUSY;
+
+	if (!mutex_trylock(&bo->mappings.lock))
+		return -EBUSY;
+
+	panfrost_gem_teardown_mappings_locked(bo);
+
+	drm_gem_shmem_purge_locked(&bo->base);
+
+	mutex_unlock(&bo->mappings.lock);
+
+	return 0;
+}
+
 static const struct drm_gem_object_funcs panfrost_gem_funcs = {
 	.free = panfrost_gem_free_object,
 	.open = panfrost_gem_open,
@@ -207,6 +216,7 @@ static const struct drm_gem_object_funcs panfrost_gem_funcs = {
 	.vunmap = drm_gem_shmem_object_vunmap_locked,
 	.mmap = drm_gem_shmem_object_mmap,
 	.vm_ops = &drm_gem_shmem_vm_ops,
+	.evict = panfrost_shmem_evict,
 };
 
 /**
diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.h b/drivers/gpu/drm/panfrost/panfrost_gem.h
index ad2877eeeccd..6ad1bcedb932 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gem.h
+++ b/drivers/gpu/drm/panfrost/panfrost_gem.h
@@ -30,12 +30,6 @@ struct panfrost_gem_object {
 		struct mutex lock;
 	} mappings;
 
-	/*
-	 * Count the number of jobs referencing this BO so we don't let the
-	 * shrinker reclaim this object prematurely.
-	 */
-	atomic_t gpu_usecount;
-
 	bool noexec		:1;
 	bool is_heap		:1;
 };
@@ -81,7 +75,4 @@ panfrost_gem_mapping_get(struct panfrost_gem_object *bo,
 void panfrost_gem_mapping_put(struct panfrost_gem_mapping *mapping);
 void panfrost_gem_teardown_mappings_locked(struct panfrost_gem_object *bo);
 
-void panfrost_gem_shrinker_init(struct drm_device *dev);
-void panfrost_gem_shrinker_cleanup(struct drm_device *dev);
-
 #endif /* __PANFROST_GEM_H__ */
diff --git a/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c b/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
deleted file mode 100644
index eb810403b027..000000000000
--- a/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
+++ /dev/null
@@ -1,129 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Copyright (C) 2019 Arm Ltd.
- *
- * Based on msm_gem_freedreno.c:
- * Copyright (C) 2016 Red Hat
- * Author: Rob Clark <robdclark@gmail.com>
- */
-
-#include <linux/list.h>
-
-#include <drm/drm_device.h>
-#include <drm/drm_gem_shmem_helper.h>
-
-#include "panfrost_device.h"
-#include "panfrost_gem.h"
-#include "panfrost_mmu.h"
-
-static bool panfrost_gem_shmem_is_purgeable(struct drm_gem_shmem_object *shmem)
-{
-	return (shmem->madv > 0) &&
-		!kref_read(&shmem->pages_pin_count) && shmem->sgt &&
-		!shmem->base.dma_buf && !shmem->base.import_attach;
-}
-
-static unsigned long
-panfrost_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc)
-{
-	struct panfrost_device *pfdev =
-		container_of(shrinker, struct panfrost_device, shrinker);
-	struct drm_gem_shmem_object *shmem;
-	unsigned long count = 0;
-
-	if (!mutex_trylock(&pfdev->shrinker_lock))
-		return 0;
-
-	list_for_each_entry(shmem, &pfdev->shrinker_list, madv_list) {
-		if (panfrost_gem_shmem_is_purgeable(shmem))
-			count += shmem->base.size >> PAGE_SHIFT;
-	}
-
-	mutex_unlock(&pfdev->shrinker_lock);
-
-	return count;
-}
-
-static bool panfrost_gem_purge(struct drm_gem_object *obj)
-{
-	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
-	struct panfrost_gem_object *bo = to_panfrost_bo(obj);
-	bool ret = false;
-
-	if (atomic_read(&bo->gpu_usecount))
-		return false;
-
-	if (!mutex_trylock(&bo->mappings.lock))
-		return false;
-
-	if (!dma_resv_trylock(shmem->base.resv))
-		goto unlock_mappings;
-
-	panfrost_gem_teardown_mappings_locked(bo);
-	drm_gem_shmem_purge_locked(&bo->base);
-	ret = true;
-
-	dma_resv_unlock(shmem->base.resv);
-
-unlock_mappings:
-	mutex_unlock(&bo->mappings.lock);
-	return ret;
-}
-
-static unsigned long
-panfrost_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc)
-{
-	struct panfrost_device *pfdev =
-		container_of(shrinker, struct panfrost_device, shrinker);
-	struct drm_gem_shmem_object *shmem, *tmp;
-	unsigned long freed = 0;
-
-	if (!mutex_trylock(&pfdev->shrinker_lock))
-		return SHRINK_STOP;
-
-	list_for_each_entry_safe(shmem, tmp, &pfdev->shrinker_list, madv_list) {
-		if (freed >= sc->nr_to_scan)
-			break;
-		if (drm_gem_shmem_is_purgeable(shmem) &&
-		    panfrost_gem_purge(&shmem->base)) {
-			freed += shmem->base.size >> PAGE_SHIFT;
-			list_del_init(&shmem->madv_list);
-		}
-	}
-
-	mutex_unlock(&pfdev->shrinker_lock);
-
-	if (freed > 0)
-		pr_info_ratelimited("Purging %lu bytes\n", freed << PAGE_SHIFT);
-
-	return freed;
-}
-
-/**
- * panfrost_gem_shrinker_init - Initialize panfrost shrinker
- * @dev: DRM device
- *
- * This function registers and sets up the panfrost shrinker.
- */
-void panfrost_gem_shrinker_init(struct drm_device *dev)
-{
-	struct panfrost_device *pfdev = dev->dev_private;
-	pfdev->shrinker.count_objects = panfrost_gem_shrinker_count;
-	pfdev->shrinker.scan_objects = panfrost_gem_shrinker_scan;
-	pfdev->shrinker.seeks = DEFAULT_SEEKS;
-	WARN_ON(register_shrinker(&pfdev->shrinker, "drm-panfrost"));
-}
-
-/**
- * panfrost_gem_shrinker_cleanup - Clean up panfrost shrinker
- * @dev: DRM device
- *
- * This function unregisters the panfrost shrinker.
- */
-void panfrost_gem_shrinker_cleanup(struct drm_device *dev)
-{
-	struct panfrost_device *pfdev = dev->dev_private;
-
-	if (pfdev->shrinker.nr_deferred) {
-		unregister_shrinker(&pfdev->shrinker);
-	}
-}
diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c
index dbc597ab46fb..98d9751d2b2c 100644
--- a/drivers/gpu/drm/panfrost/panfrost_job.c
+++ b/drivers/gpu/drm/panfrost/panfrost_job.c
@@ -272,6 +272,19 @@ static void panfrost_attach_object_fences(struct drm_gem_object **bos,
 		dma_resv_add_fence(bos[i]->resv, fence, DMA_RESV_USAGE_WRITE);
 }
 
+static int panfrost_objects_prepare(struct drm_gem_object **bos, int bo_count)
+{
+	struct panfrost_gem_object *bo;
+	int ret = 0;
+
+	while (!ret && bo_count--) {
+		bo = to_panfrost_bo(bos[bo_count]);
+		ret = bo->base.madv ? -ENOMEM : 0;
+	}
+
+	return ret;
+}
+
 int panfrost_job_push(struct panfrost_job *job)
 {
 	struct panfrost_device *pfdev = job->pfdev;
@@ -283,6 +296,10 @@ int panfrost_job_push(struct panfrost_job *job)
 	if (ret)
 		return ret;
 
+	ret = panfrost_objects_prepare(job->bos, job->bo_count);
+	if (ret)
+		goto unlock;
+
 	mutex_lock(&pfdev->sched_lock);
 	drm_sched_job_arm(&job->base);
 
@@ -324,7 +341,6 @@ static void panfrost_job_cleanup(struct kref *ref)
 			if (!job->mappings[i])
 				break;
 
-			atomic_dec(&job->mappings[i]->obj->gpu_usecount);
 			panfrost_gem_mapping_put(job->mappings[i]);
 		}
 		kvfree(job->mappings);
diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h
index e10ba533f74d..e52921d03c6f 100644
--- a/include/drm/drm_gem_shmem_helper.h
+++ b/include/drm/drm_gem_shmem_helper.h
@@ -60,13 +60,6 @@ struct drm_gem_shmem_object {
 	 */
 	int madv;
 
-	/**
-	 * @madv_list: List entry for madvise tracking
-	 *
-	 * Typically used by drivers to track purgeable objects
-	 */
-	struct list_head madv_list;
-
 	/**
 	 * @sgt: Scatter/gather table for imported PRIME buffers
 	 */
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 10/23] locking/refcount, kref: Add kref_put_ww_mutex()
  2023-08-27 17:54 ` [PATCH v15 10/23] locking/refcount, kref: Add kref_put_ww_mutex() Dmitry Osipenko
@ 2023-08-28  9:26   ` Boris Brezillon
  2023-08-29  2:28     ` Dmitry Osipenko
  0 siblings, 1 reply; 53+ messages in thread
From: Boris Brezillon @ 2023-08-28  9:26 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Emma Anholt, Melissa Wen, Will Deacon, Peter Zijlstra,
	Boqun Feng, Mark Rutland, dri-devel, linux-kernel, kernel,
	virtualization, intel-gfx

On Sun, 27 Aug 2023 20:54:36 +0300
Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:

> Introduce kref_put_ww_mutex() helper that will handle the wait-wound
> mutex auto-locking on kref_put(). This helper is wanted by DRM drivers
> that extensively use dma-reservation locking which in turns uses ww-mutex.
> 
> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
> ---
>  include/linux/kref.h     | 12 ++++++++++++
>  include/linux/refcount.h |  5 +++++
>  lib/refcount.c           | 34 ++++++++++++++++++++++++++++++++++
>  3 files changed, 51 insertions(+)
> 
> diff --git a/include/linux/kref.h b/include/linux/kref.h
> index d32e21a2538c..b2d8dc6e9ae0 100644
> --- a/include/linux/kref.h
> +++ b/include/linux/kref.h
> @@ -90,6 +90,18 @@ static inline int kref_put_lock(struct kref *kref,
>  	return 0;
>  }
>  
> +static inline int kref_put_ww_mutex(struct kref *kref,
> +				    void (*release)(struct kref *kref),
> +				    struct ww_mutex *lock,
> +				    struct ww_acquire_ctx *ctx)
> +{
> +	if (refcount_dec_and_ww_mutex_lock(&kref->refcount, lock, ctx)) {
> +		release(kref);
> +		return 1;
> +	}
> +	return 0;
> +}
> +
>  /**
>   * kref_get_unless_zero - Increment refcount for object unless it is zero.
>   * @kref: object.
> diff --git a/include/linux/refcount.h b/include/linux/refcount.h
> index a62fcca97486..be9ad272bc77 100644
> --- a/include/linux/refcount.h
> +++ b/include/linux/refcount.h
> @@ -99,6 +99,8 @@
>  #include <linux/spinlock_types.h>
>  
>  struct mutex;
> +struct ww_mutex;
> +struct ww_acquire_ctx;
>  
>  /**
>   * typedef refcount_t - variant of atomic_t specialized for reference counts
> @@ -366,4 +368,7 @@ extern __must_check bool refcount_dec_and_lock(refcount_t *r, spinlock_t *lock)
>  extern __must_check bool refcount_dec_and_lock_irqsave(refcount_t *r,
>  						       spinlock_t *lock,
>  						       unsigned long *flags) __cond_acquires(lock);
> +extern __must_check bool refcount_dec_and_ww_mutex_lock(refcount_t *r,
> +							struct ww_mutex *lock,
> +							struct ww_acquire_ctx *ctx) __cond_acquires(&lock->base);
>  #endif /* _LINUX_REFCOUNT_H */
> diff --git a/lib/refcount.c b/lib/refcount.c
> index a207a8f22b3c..3f6fd0ceed02 100644
> --- a/lib/refcount.c
> +++ b/lib/refcount.c
> @@ -6,6 +6,7 @@
>  #include <linux/mutex.h>
>  #include <linux/refcount.h>
>  #include <linux/spinlock.h>
> +#include <linux/ww_mutex.h>
>  #include <linux/bug.h>
>  
>  #define REFCOUNT_WARN(str)	WARN_ONCE(1, "refcount_t: " str ".\n")
> @@ -184,3 +185,36 @@ bool refcount_dec_and_lock_irqsave(refcount_t *r, spinlock_t *lock,
>  	return true;
>  }
>  EXPORT_SYMBOL(refcount_dec_and_lock_irqsave);
> +
> +/**
> + * refcount_dec_and_ww_mutex_lock - return holding ww-mutex if able to
> + *                                  decrement refcount to 0
> + * @r: the refcount
> + * @lock: the ww-mutex to be locked
> + * @ctx: wait-wound context
> + *
> + * Similar to atomic_dec_and_lock(), it will WARN on underflow and fail to
> + * decrement when saturated at REFCOUNT_SATURATED.
> + *
> + * Provides release memory ordering, such that prior loads and stores are done
> + * before, and provides a control dependency such that free() must come after.
> + * See the comment on top.
> + *
> + * Return: true and hold ww-mutex lock if able to decrement refcount to 0,
> + *         false otherwise
> + */
> +bool refcount_dec_and_ww_mutex_lock(refcount_t *r, struct ww_mutex *lock,
> +				    struct ww_acquire_ctx *ctx)
> +{
> +	if (refcount_dec_not_one(r))
> +		return false;
> +
> +	ww_mutex_lock(lock, ctx);

Unless I'm wrong, ww_mutex_lock() can return -EDEADLK when ctx !=
NULL, in which case, the lock is not held when it returns. Question is,
do we really have a use case for ctx != NULL in that kref_put_ww_mutex()
path. If we need to acquire other ww_locks, this lock, and the other
locks should have been acquired beforehand, and we can simply call
kref_put() when we want to release the ref on the resource.

> +	if (!refcount_dec_and_test(r)) {
> +		ww_mutex_unlock(lock);
> +		return false;
> +	}
> +
> +	return true;
> +}
> +EXPORT_SYMBOL(refcount_dec_and_ww_mutex_lock);


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 12/23] drm/shmem-helper: Add and use pages_pin_count
  2023-08-27 17:54 ` [PATCH v15 12/23] drm/shmem-helper: Add and use pages_pin_count Dmitry Osipenko
@ 2023-08-28  9:38   ` Boris Brezillon
  2023-08-28 11:46   ` Boris Brezillon
  1 sibling, 0 replies; 53+ messages in thread
From: Boris Brezillon @ 2023-08-28  9:38 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Emma Anholt, Melissa Wen, Will Deacon, Peter Zijlstra,
	Boqun Feng, Mark Rutland, dri-devel, linux-kernel, kernel,
	virtualization, intel-gfx

On Sun, 27 Aug 2023 20:54:38 +0300
Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:

> Add separate pages_pin_count for tracking of whether drm-shmem pages are
> moveable or not. With the addition of memory shrinker support to drm-shmem,
> the pages_use_count will no longer determine whether pages are hard-pinned
> in memory, but whether pages exit and are soft-pinned (and could be swapped

				^exist

> out). The pages_pin_count > 1 will hard-pin pages in memory.
> 
> Suggested-by: Boris Brezillon <boris.brezillon@collabora.com>
> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
> ---
>  drivers/gpu/drm/drm_gem_shmem_helper.c | 22 +++++++++++++++++-----
>  include/drm/drm_gem_shmem_helper.h     | 10 ++++++++++
>  2 files changed, 27 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
> index d545d3d227d7..1a7e5c332fd8 100644
> --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
> +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
> @@ -234,14 +234,22 @@ static int drm_gem_shmem_pin_locked(struct drm_gem_shmem_object *shmem)
>  
>  	dma_resv_assert_held(shmem->base.resv);
>  
> +	if (kref_get_unless_zero(&shmem->pages_pin_count))
> +		return 0;
> +
>  	ret = drm_gem_shmem_get_pages_locked(shmem);
> +	if (!ret)
> +		kref_init(&shmem->pages_pin_count);
>  
>  	return ret;
>  }
>  
> -static void drm_gem_shmem_unpin_locked(struct drm_gem_shmem_object *shmem)
> +static void drm_gem_shmem_kref_unpin_pages(struct kref *kref)
>  {
> -	dma_resv_assert_held(shmem->base.resv);
> +	struct drm_gem_shmem_object *shmem;
> +
> +	shmem = container_of(kref, struct drm_gem_shmem_object,
> +			     pages_pin_count);
>  
>  	drm_gem_shmem_put_pages_locked(shmem);
>  }
> @@ -263,6 +271,9 @@ int drm_gem_shmem_pin(struct drm_gem_shmem_object *shmem)
>  
>  	drm_WARN_ON(obj->dev, obj->import_attach);
>  
> +	if (kref_get_unless_zero(&shmem->pages_pin_count))
> +		return 0;
> +
>  	ret = dma_resv_lock_interruptible(shmem->base.resv, NULL);
>  	if (ret)
>  		return ret;
> @@ -286,9 +297,10 @@ void drm_gem_shmem_unpin(struct drm_gem_shmem_object *shmem)
>  
>  	drm_WARN_ON(obj->dev, obj->import_attach);
>  
> -	dma_resv_lock(shmem->base.resv, NULL);
> -	drm_gem_shmem_unpin_locked(shmem);
> -	dma_resv_unlock(shmem->base.resv);
> +	if (kref_put_dma_resv(&shmem->pages_pin_count,
> +			      drm_gem_shmem_kref_unpin_pages,
> +			      obj->resv, NULL))
> +		dma_resv_unlock(obj->resv);
>  }
>  EXPORT_SYMBOL_GPL(drm_gem_shmem_unpin);
>  
> diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h
> index ec2d8b24e3cf..afb7cd671e2a 100644
> --- a/include/drm/drm_gem_shmem_helper.h
> +++ b/include/drm/drm_gem_shmem_helper.h
> @@ -39,6 +39,16 @@ struct drm_gem_shmem_object {
>  	 */
>  	unsigned int pages_use_count;
>  
> +	/**
> +	 * @pages_pin_count:
> +	 *
> +	 * Reference count on the pinned pages table.
> +	 * The pages allowed to be evicted and purged by memory
> +	 * shrinker only when the count is zero, otherwise pages
> +	 * are hard-pinned in memory.
> +	 */
> +	struct kref pages_pin_count;
> +
>  	/**
>  	 * @madv: State for madvise
>  	 *


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 16/23] drm/shmem-helper: Use kref for vmap_use_count
  2023-08-27 17:54 ` [PATCH v15 16/23] drm/shmem-helper: Use kref for vmap_use_count Dmitry Osipenko
@ 2023-08-28 10:00   ` Boris Brezillon
  2023-09-02 20:22     ` Dmitry Osipenko
  0 siblings, 1 reply; 53+ messages in thread
From: Boris Brezillon @ 2023-08-28 10:00 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Emma Anholt, Melissa Wen, Will Deacon, Peter Zijlstra,
	Boqun Feng, Mark Rutland, dri-devel, linux-kernel, kernel,
	virtualization, intel-gfx

On Sun, 27 Aug 2023 20:54:42 +0300
Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:

> Use kref helper for vmap_use_count to make refcounting consistent with
> pages_use_count and pages_pin_count that use kref. This will allow to
> optimize unlocked vmappings by skipping reservation locking if refcnt > 1.

The core is taking the resv lock before calling ->v[un]map(), so
switching to a kref sounds a bit premature/useless, unless there are
plans to delegate the locking to the drivers. The only thing it brings
is standard overflow/underflow checks. Not really sure it's worth
transitioning to a kref for this field until we have a real use case.

> 
> Suggested-by: Boris Brezillon <boris.brezillon@collabora.com>
> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
> ---
>  drivers/gpu/drm/drm_gem_shmem_helper.c | 37 ++++++++++++++------------
>  include/drm/drm_gem_shmem_helper.h     |  2 +-
>  2 files changed, 21 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
> index 17a0177acb5d..d96fee3d6166 100644
> --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
> +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
> @@ -144,7 +144,7 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
>  	} else if (!shmem->imported_sgt) {
>  		dma_resv_lock(shmem->base.resv, NULL);
>  
> -		drm_WARN_ON(obj->dev, shmem->vmap_use_count);
> +		drm_WARN_ON(obj->dev, kref_read(&shmem->vmap_use_count));
>  
>  		if (shmem->sgt) {
>  			dma_unmap_sgtable(obj->dev->dev, shmem->sgt,
> @@ -359,23 +359,25 @@ int drm_gem_shmem_vmap_locked(struct drm_gem_shmem_object *shmem,
>  
>  		dma_resv_assert_held(shmem->base.resv);
>  
> -		if (shmem->vmap_use_count++ > 0) {
> +		if (kref_get_unless_zero(&shmem->vmap_use_count)) {
>  			iosys_map_set_vaddr(map, shmem->vaddr);
>  			return 0;
>  		}
>  
>  		ret = drm_gem_shmem_pin_locked(shmem);
>  		if (ret)
> -			goto err_zero_use;
> +			return ret;
>  
>  		if (shmem->map_wc)
>  			prot = pgprot_writecombine(prot);
>  		shmem->vaddr = vmap(shmem->pages, obj->size >> PAGE_SHIFT,
>  				    VM_MAP, prot);
> -		if (!shmem->vaddr)
> +		if (!shmem->vaddr) {
>  			ret = -ENOMEM;
> -		else
> +		} else {
>  			iosys_map_set_vaddr(map, shmem->vaddr);
> +			kref_init(&shmem->vmap_use_count);
> +		}
>  	}
>  
>  	if (ret) {
> @@ -388,13 +390,22 @@ int drm_gem_shmem_vmap_locked(struct drm_gem_shmem_object *shmem,
>  err_put_pages:
>  	if (!obj->import_attach)
>  		drm_gem_shmem_unpin_locked(shmem);
> -err_zero_use:
> -	shmem->vmap_use_count = 0;
>  
>  	return ret;
>  }
>  EXPORT_SYMBOL_GPL(drm_gem_shmem_vmap_locked);
>  
> +static void drm_gem_shmem_kref_vunmap(struct kref *kref)
> +{
> +	struct drm_gem_shmem_object *shmem;
> +
> +	shmem = container_of(kref, struct drm_gem_shmem_object,
> +			     vmap_use_count);
> +
> +	vunmap(shmem->vaddr);
> +	drm_gem_shmem_unpin_locked(shmem);
> +}
> +
>  /*
>   * drm_gem_shmem_vunmap_locked - Unmap a virtual mapping for a shmem GEM object
>   * @shmem: shmem GEM object
> @@ -416,15 +427,7 @@ void drm_gem_shmem_vunmap_locked(struct drm_gem_shmem_object *shmem,
>  		dma_buf_vunmap(obj->import_attach->dmabuf, map);
>  	} else {
>  		dma_resv_assert_held(shmem->base.resv);
> -
> -		if (drm_WARN_ON_ONCE(obj->dev, !shmem->vmap_use_count))
> -			return;
> -
> -		if (--shmem->vmap_use_count > 0)
> -			return;
> -
> -		vunmap(shmem->vaddr);
> -		drm_gem_shmem_unpin_locked(shmem);
> +		kref_put(&shmem->vmap_use_count, drm_gem_shmem_kref_vunmap);
>  	}
>  
>  	shmem->vaddr = NULL;
> @@ -663,7 +666,7 @@ void drm_gem_shmem_print_info(const struct drm_gem_shmem_object *shmem,
>  		return;
>  
>  	drm_printf_indent(p, indent, "pages_use_count=%u\n", kref_read(&shmem->pages_use_count));
> -	drm_printf_indent(p, indent, "vmap_use_count=%u\n", shmem->vmap_use_count);
> +	drm_printf_indent(p, indent, "vmap_use_count=%u\n", kref_read(&shmem->vmap_use_count));
>  	drm_printf_indent(p, indent, "vaddr=%p\n", shmem->vaddr);
>  }
>  EXPORT_SYMBOL_GPL(drm_gem_shmem_print_info);
> diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h
> index 400ecd63f45f..0e0ccd380f66 100644
> --- a/include/drm/drm_gem_shmem_helper.h
> +++ b/include/drm/drm_gem_shmem_helper.h
> @@ -81,7 +81,7 @@ struct drm_gem_shmem_object {
>  	 * Reference count on the virtual address.
>  	 * The address are un-mapped when the count reaches zero.
>  	 */
> -	unsigned int vmap_use_count;
> +	struct kref vmap_use_count;
>  
>  	/**
>  	 * @got_sgt:


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 17/23] drm/shmem-helper: Add and use drm_gem_shmem_resv_assert_held() helper
  2023-08-27 17:54 ` [PATCH v15 17/23] drm/shmem-helper: Add and use drm_gem_shmem_resv_assert_held() helper Dmitry Osipenko
@ 2023-08-28 10:12   ` Boris Brezillon
  2023-08-29  2:34     ` Dmitry Osipenko
  0 siblings, 1 reply; 53+ messages in thread
From: Boris Brezillon @ 2023-08-28 10:12 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Emma Anholt, Melissa Wen, Will Deacon, Peter Zijlstra,
	Boqun Feng, Mark Rutland, dri-devel, linux-kernel, kernel,
	virtualization, intel-gfx

On Sun, 27 Aug 2023 20:54:43 +0300
Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:

> In a preparation of adding drm-shmem memory shrinker, move all reservation
> locking lockdep checks to use new drm_gem_shmem_resv_assert_held() that
> will resolve spurious lockdep warning about wrong locking order vs
> fs_reclam code paths during freeing of shmem GEM, where lockdep isn't
> aware that it's impossible to have locking contention with the fs_reclam
> at this special time.
> 
> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
> ---
>  drivers/gpu/drm/drm_gem_shmem_helper.c | 37 +++++++++++++++++---------
>  1 file changed, 25 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
> index d96fee3d6166..ca5da976aafa 100644
> --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
> +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
> @@ -128,6 +128,23 @@ struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t
>  }
>  EXPORT_SYMBOL_GPL(drm_gem_shmem_create);
>  
> +static void drm_gem_shmem_resv_assert_held(struct drm_gem_shmem_object *shmem)
> +{
> +	/*
> +	 * Destroying the object is a special case.. drm_gem_shmem_free()
> +	 * calls many things that WARN_ON if the obj lock is not held.  But
> +	 * acquiring the obj lock in drm_gem_shmem_free() can cause a locking
> +	 * order inversion between reservation_ww_class_mutex and fs_reclaim.
> +	 *
> +	 * This deadlock is not actually possible, because no one should
> +	 * be already holding the lock when drm_gem_shmem_free() is called.
> +	 * Unfortunately lockdep is not aware of this detail.  So when the
> +	 * refcount drops to zero, we pretend it is already locked.
> +	 */
> +	if (kref_read(&shmem->base.refcount))
> +		drm_gem_shmem_resv_assert_held(shmem);
> +}
> +
>  /**
>   * drm_gem_shmem_free - Free resources associated with a shmem GEM object
>   * @shmem: shmem GEM object to free
> @@ -142,8 +159,6 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
>  	if (obj->import_attach) {
>  		drm_prime_gem_destroy(obj, shmem->sgt);
>  	} else if (!shmem->imported_sgt) {
> -		dma_resv_lock(shmem->base.resv, NULL);
> -
>  		drm_WARN_ON(obj->dev, kref_read(&shmem->vmap_use_count));
>  
>  		if (shmem->sgt) {
> @@ -156,8 +171,6 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
>  			drm_gem_shmem_put_pages_locked(shmem);

AFAICT, drm_gem_shmem_put_pages_locked() is the only function that's
called in the free path and would complain about resv-lock not being
held. I think I'd feel more comfortable if we were adding a
drm_gem_shmem_free_pages() function that did everything
drm_gem_shmem_put_pages_locked() does except for the lock_held() check
and the refcount dec, and have it called here (and in
drm_gem_shmem_put_pages_locked()). This way we can keep using
dma_resv_assert_held() instead of having our own variant.

>  
>  		drm_WARN_ON(obj->dev, kref_read(&shmem->pages_use_count));
> -
> -		dma_resv_unlock(shmem->base.resv);
>  	}
>  
>  	drm_gem_object_release(obj);
> @@ -170,7 +183,7 @@ static int drm_gem_shmem_get_pages_locked(struct drm_gem_shmem_object *shmem)
>  	struct drm_gem_object *obj = &shmem->base;
>  	struct page **pages;
>  
> -	dma_resv_assert_held(shmem->base.resv);
> +	drm_gem_shmem_resv_assert_held(shmem);
>  
>  	if (kref_get_unless_zero(&shmem->pages_use_count))
>  		return 0;
> @@ -228,7 +241,7 @@ static void drm_gem_shmem_kref_release_pages(struct kref *kref)
>   */
>  void drm_gem_shmem_put_pages_locked(struct drm_gem_shmem_object *shmem)
>  {
> -	dma_resv_assert_held(shmem->base.resv);
> +	drm_gem_shmem_resv_assert_held(shmem);
>  
>  	kref_put(&shmem->pages_use_count, drm_gem_shmem_kref_release_pages);
>  }
> @@ -252,7 +265,7 @@ static int drm_gem_shmem_pin_locked(struct drm_gem_shmem_object *shmem)
>  {
>  	int ret;
>  
> -	dma_resv_assert_held(shmem->base.resv);
> +	drm_gem_shmem_resv_assert_held(shmem);
>  
>  	if (kref_get_unless_zero(&shmem->pages_pin_count))
>  		return 0;
> @@ -276,7 +289,7 @@ static void drm_gem_shmem_kref_unpin_pages(struct kref *kref)
>  
>  static void drm_gem_shmem_unpin_locked(struct drm_gem_shmem_object *shmem)
>  {
> -	dma_resv_assert_held(shmem->base.resv);
> +	drm_gem_shmem_resv_assert_held(shmem);
>  
>  	kref_put(&shmem->pages_pin_count, drm_gem_shmem_kref_unpin_pages);
>  }
> @@ -357,7 +370,7 @@ int drm_gem_shmem_vmap_locked(struct drm_gem_shmem_object *shmem,
>  	} else {
>  		pgprot_t prot = PAGE_KERNEL;
>  
> -		dma_resv_assert_held(shmem->base.resv);
> +		drm_gem_shmem_resv_assert_held(shmem);
>  
>  		if (kref_get_unless_zero(&shmem->vmap_use_count)) {
>  			iosys_map_set_vaddr(map, shmem->vaddr);
> @@ -426,7 +439,7 @@ void drm_gem_shmem_vunmap_locked(struct drm_gem_shmem_object *shmem,
>  	if (obj->import_attach) {
>  		dma_buf_vunmap(obj->import_attach->dmabuf, map);
>  	} else {
> -		dma_resv_assert_held(shmem->base.resv);
> +		drm_gem_shmem_resv_assert_held(shmem);
>  		kref_put(&shmem->vmap_use_count, drm_gem_shmem_kref_vunmap);
>  	}
>  
> @@ -462,7 +475,7 @@ drm_gem_shmem_create_with_handle(struct drm_file *file_priv,
>   */
>  int drm_gem_shmem_madvise_locked(struct drm_gem_shmem_object *shmem, int madv)
>  {
> -	dma_resv_assert_held(shmem->base.resv);
> +	drm_gem_shmem_resv_assert_held(shmem);
>  
>  	if (shmem->madv >= 0)
>  		shmem->madv = madv;
> @@ -478,7 +491,7 @@ void drm_gem_shmem_purge_locked(struct drm_gem_shmem_object *shmem)
>  	struct drm_gem_object *obj = &shmem->base;
>  	struct drm_device *dev = obj->dev;
>  
> -	dma_resv_assert_held(shmem->base.resv);
> +	drm_gem_shmem_resv_assert_held(shmem);
>  
>  	drm_WARN_ON(obj->dev, !drm_gem_shmem_is_purgeable(shmem));
>  


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 11/23] dma-resv: Add kref_put_dma_resv()
  2023-08-27 17:54 ` [PATCH v15 11/23] dma-resv: Add kref_put_dma_resv() Dmitry Osipenko
@ 2023-08-28 10:21   ` Christian König
  0 siblings, 0 replies; 53+ messages in thread
From: Christian König @ 2023-08-28 10:21 UTC (permalink / raw)
  To: Dmitry Osipenko, David Airlie, Gerd Hoffmann, Gurchetan Singh,
	Chia-I Wu, Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Qiang Yu, Steven Price, Boris Brezillon,
	Emma Anholt, Melissa Wen, Will Deacon, Peter Zijlstra,
	Boqun Feng, Mark Rutland
  Cc: dri-devel, linux-kernel, kernel, virtualization, intel-gfx

Am 27.08.23 um 19:54 schrieb Dmitry Osipenko:
> Add simple kref_put_dma_resv() helper that wraps around kref_put_ww_mutex()
> for drivers that needs to lock dma-resv on kref_put().
>
> It's not possible to easily add this helper to kref.h because of the
> headers inclusion dependency, hence add it to dma-resv.h.

I was never really a big fan of kref_put_mutex() in the first place.

The main advantage comes from the included memory barrier, but this 
actually doesn't work like most people think it works and is usually 
pretty dangerous.

And IIRC this was done because of the some special behavior mutexes have 
with memory barriers and that isn't necessary with ww-mutex.

Christian.

>
> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
> ---
>   include/linux/dma-resv.h | 9 +++++++++
>   1 file changed, 9 insertions(+)
>
> diff --git a/include/linux/dma-resv.h b/include/linux/dma-resv.h
> index 8d0e34dad446..c5cf302e4194 100644
> --- a/include/linux/dma-resv.h
> +++ b/include/linux/dma-resv.h
> @@ -41,6 +41,7 @@
>   
>   #include <linux/ww_mutex.h>
>   #include <linux/dma-fence.h>
> +#include <linux/kref.h>
>   #include <linux/slab.h>
>   #include <linux/seqlock.h>
>   #include <linux/rcupdate.h>
> @@ -464,6 +465,14 @@ static inline void dma_resv_unlock(struct dma_resv *obj)
>   	ww_mutex_unlock(&obj->lock);
>   }
>   
> +static inline int kref_put_dma_resv(struct kref *kref,
> +				    void (*release)(struct kref *kref),
> +				    struct dma_resv *resv,
> +				    struct ww_acquire_ctx *ctx)
> +{
> +	return kref_put_ww_mutex(kref, release, &resv->lock, ctx);
> +}
> +
>   void dma_resv_init(struct dma_resv *obj);
>   void dma_resv_fini(struct dma_resv *obj);
>   int dma_resv_reserve_fences(struct dma_resv *obj, unsigned int num_fences);


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 02/23] drm/shmem-helper: Use flag for tracking page count bumped by get_pages_sgt()
  2023-08-27 17:54 ` [PATCH v15 02/23] drm/shmem-helper: Use flag for tracking page count bumped by get_pages_sgt() Dmitry Osipenko
@ 2023-08-28 10:55   ` Boris Brezillon
  2023-09-02 18:28     ` Dmitry Osipenko
  0 siblings, 1 reply; 53+ messages in thread
From: Boris Brezillon @ 2023-08-28 10:55 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Emma Anholt, Melissa Wen, Will Deacon, Peter Zijlstra,
	Boqun Feng, Mark Rutland, dri-devel, linux-kernel, kernel,
	virtualization, intel-gfx

On Sun, 27 Aug 2023 20:54:28 +0300
Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:

> Use separate flag for tracking page count bumped by shmem->sgt to avoid
> imbalanced page counter during of drm_gem_shmem_free() time. It's fragile
> to assume that populated shmem->pages at a freeing time means that the
> count was bumped by drm_gem_shmem_get_pages_sgt(), using a flag removes
> the ambiguity.
> 
> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
> ---
>  drivers/gpu/drm/drm_gem_shmem_helper.c | 3 ++-
>  drivers/gpu/drm/lima/lima_gem.c        | 1 +
>  include/drm/drm_gem_shmem_helper.h     | 7 +++++++
>  3 files changed, 10 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
> index 78d9cf2355a5..db20b9123891 100644
> --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
> +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
> @@ -152,7 +152,7 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
>  			sg_free_table(shmem->sgt);
>  			kfree(shmem->sgt);
>  		}
> -		if (shmem->pages)
> +		if (shmem->got_sgt)
>  			drm_gem_shmem_put_pages(shmem);

Can't we just move this drm_gem_shmem_put_pages() call in the
if (shmem->sgt) block?

>  
>  		drm_WARN_ON(obj->dev, shmem->pages_use_count);
> @@ -687,6 +687,7 @@ static struct sg_table *drm_gem_shmem_get_pages_sgt_locked(struct drm_gem_shmem_
>  	if (ret)
>  		goto err_free_sgt;
>  
> +	shmem->got_sgt = true;
>  	shmem->sgt = sgt;
>  
>  	return sgt;
> diff --git a/drivers/gpu/drm/lima/lima_gem.c b/drivers/gpu/drm/lima/lima_gem.c
> index 4f9736e5f929..28602302c281 100644
> --- a/drivers/gpu/drm/lima/lima_gem.c
> +++ b/drivers/gpu/drm/lima/lima_gem.c
> @@ -89,6 +89,7 @@ int lima_heap_alloc(struct lima_bo *bo, struct lima_vm *vm)
>  	}
>  
>  	*bo->base.sgt = sgt;
> +	bo->base.got_sgt = true;
>  
>  	if (vm) {
>  		ret = lima_vm_map_bo(vm, bo, old_size >> PAGE_SHIFT);
> diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h
> index ec70a98a8fe1..f87124629bb5 100644
> --- a/include/drm/drm_gem_shmem_helper.h
> +++ b/include/drm/drm_gem_shmem_helper.h
> @@ -73,6 +73,13 @@ struct drm_gem_shmem_object {
>  	 */
>  	unsigned int vmap_use_count;
>  
> +	/**
> +	 * @got_sgt:
> +	 *
> +	 * True if SG table was retrieved using drm_gem_shmem_get_pages_sgt()
> +	 */
> +	bool got_sgt : 1;
> +
>  	/**
>  	 * @imported_sgt:
>  	 *


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 01/23] drm/shmem-helper: Fix UAF in error path when freeing SGT of imported GEM
  2023-08-27 17:54 ` [PATCH v15 01/23] drm/shmem-helper: Fix UAF in error path when freeing SGT of imported GEM Dmitry Osipenko
@ 2023-08-28 11:16   ` Boris Brezillon
  2023-09-02 18:15     ` Dmitry Osipenko
  0 siblings, 1 reply; 53+ messages in thread
From: Boris Brezillon @ 2023-08-28 11:16 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Emma Anholt, Melissa Wen, Will Deacon, Peter Zijlstra,
	Boqun Feng, Mark Rutland, dri-devel, linux-kernel, kernel,
	virtualization, intel-gfx

On Sun, 27 Aug 2023 20:54:27 +0300
Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:

> Freeing drm-shmem GEM right after creating it using
> drm_gem_shmem_prime_import_sg_table() frees SGT of the imported dma-buf
> and then dma-buf frees this SGT second time.
> 
> The v3d_prime_import_sg_table() is example of a error code path where
> dma-buf's SGT is freed by drm-shmem and then it's freed second time by
> dma_buf_unmap_attachment() in drm_gem_prime_import_dev().
> 
> Add drm-shmem GEM flag telling that this is imported SGT shall not be
> treated as own SGT, fixing the use-after-free bug.
> 
> Cc: stable@vger.kernel.org
> Fixes: 2194a63a818d ("drm: Add library for shmem backed GEM objects")
> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
> ---
>  drivers/gpu/drm/drm_gem_shmem_helper.c | 3 ++-
>  include/drm/drm_gem_shmem_helper.h     | 7 +++++++
>  2 files changed, 9 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
> index a783d2245599..78d9cf2355a5 100644
> --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
> +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
> @@ -141,7 +141,7 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
>  
>  	if (obj->import_attach) {
>  		drm_prime_gem_destroy(obj, shmem->sgt);
> -	} else {
> +	} else if (!shmem->imported_sgt) {
>  		dma_resv_lock(shmem->base.resv, NULL);
>  
>  		drm_WARN_ON(obj->dev, shmem->vmap_use_count);
> @@ -758,6 +758,7 @@ drm_gem_shmem_prime_import_sg_table(struct drm_device *dev,
>  		return ERR_CAST(shmem);
>  
>  	shmem->sgt = sgt;
> +	shmem->imported_sgt = true;


I feel like adding more fields that can be used to do the is_imported()
check is going to be even more confusing. Can we instead have

	/* drm_gem_shmem_prime_import_sg_table() can be called from a
	 * driver specific ->import_sg_table() implementations that
	 * have extra failable initialization steps. Assign
	 * drm_gem_object::import_attach here (even though it's
	 * assigned in drm_gem_prime_import_dev()), so we don't end up
	 * with driver error paths calling drm_gem_shmem_free() with an
	 * imported sg_table assigned to drm_gem_shmem_object::sgt and
	 * drm_gem_object::import_attach left uninitialized.
	 */
	shmem->base.import_attach = attach;

here?

>  
>  	drm_dbg_prime(dev, "size = %zu\n", size);
>  
> diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h
> index bf0c31aa8fbe..ec70a98a8fe1 100644
> --- a/include/drm/drm_gem_shmem_helper.h
> +++ b/include/drm/drm_gem_shmem_helper.h
> @@ -73,6 +73,13 @@ struct drm_gem_shmem_object {
>  	 */
>  	unsigned int vmap_use_count;
>  
> +	/**
> +	 * @imported_sgt:
> +	 *
> +	 * True if SG table belongs to imported dma-buf.
> +	 */
> +	bool imported_sgt : 1;
> +
>  	/**
>  	 * @pages_mark_dirty_on_put:
>  	 *


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 03/23] drm/gem: Change locked/unlocked postfix of drm_gem_v/unmap() function names
  2023-08-27 17:54 ` [PATCH v15 03/23] drm/gem: Change locked/unlocked postfix of drm_gem_v/unmap() function names Dmitry Osipenko
@ 2023-08-28 11:25   ` Boris Brezillon
  0 siblings, 0 replies; 53+ messages in thread
From: Boris Brezillon @ 2023-08-28 11:25 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Emma Anholt, Melissa Wen, Will Deacon, Peter Zijlstra,
	Boqun Feng, Mark Rutland, dri-devel, linux-kernel, kernel,
	virtualization, intel-gfx

On Sun, 27 Aug 2023 20:54:29 +0300
Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:

> Make drm/gem API function names consistent by having locked function
> use the _locked postfix in the name, while the unlocked variants don't
> use the _unlocked postfix. Rename drm_gem_v/unmap() function names to
> make them consistent with the rest of the API functions.
> 
> Suggested-by: Boris Brezillon <boris.brezillon@collabora.com>
> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>

Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>

> ---
>  drivers/gpu/drm/drm_client.c                 |  6 +++---
>  drivers/gpu/drm/drm_gem.c                    | 20 ++++++++++----------
>  drivers/gpu/drm/drm_gem_framebuffer_helper.c |  6 +++---
>  drivers/gpu/drm/drm_internal.h               |  4 ++--
>  drivers/gpu/drm/drm_prime.c                  |  4 ++--
>  drivers/gpu/drm/lima/lima_sched.c            |  4 ++--
>  drivers/gpu/drm/panfrost/panfrost_dump.c     |  4 ++--
>  drivers/gpu/drm/panfrost/panfrost_perfcnt.c  |  6 +++---
>  include/drm/drm_gem.h                        |  4 ++--
>  9 files changed, 29 insertions(+), 29 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
> index 037e36f2049c..29306657117a 100644
> --- a/drivers/gpu/drm/drm_client.c
> +++ b/drivers/gpu/drm/drm_client.c
> @@ -265,7 +265,7 @@ void drm_client_dev_restore(struct drm_device *dev)
>  static void drm_client_buffer_delete(struct drm_client_buffer *buffer)
>  {
>  	if (buffer->gem) {
> -		drm_gem_vunmap_unlocked(buffer->gem, &buffer->map);
> +		drm_gem_vunmap(buffer->gem, &buffer->map);
>  		drm_gem_object_put(buffer->gem);
>  	}
>  
> @@ -349,7 +349,7 @@ drm_client_buffer_vmap(struct drm_client_buffer *buffer,
>  	 * fd_install step out of the driver backend hooks, to make that
>  	 * final step optional for internal users.
>  	 */
> -	ret = drm_gem_vmap_unlocked(buffer->gem, map);
> +	ret = drm_gem_vmap(buffer->gem, map);
>  	if (ret)
>  		return ret;
>  
> @@ -371,7 +371,7 @@ void drm_client_buffer_vunmap(struct drm_client_buffer *buffer)
>  {
>  	struct iosys_map *map = &buffer->map;
>  
> -	drm_gem_vunmap_unlocked(buffer->gem, map);
> +	drm_gem_vunmap(buffer->gem, map);
>  }
>  EXPORT_SYMBOL(drm_client_buffer_vunmap);
>  
> diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
> index 6129b89bb366..fae5832bb0bd 100644
> --- a/drivers/gpu/drm/drm_gem.c
> +++ b/drivers/gpu/drm/drm_gem.c
> @@ -1173,7 +1173,7 @@ void drm_gem_unpin(struct drm_gem_object *obj)
>  		obj->funcs->unpin(obj);
>  }
>  
> -int drm_gem_vmap(struct drm_gem_object *obj, struct iosys_map *map)
> +int drm_gem_vmap_locked(struct drm_gem_object *obj, struct iosys_map *map)
>  {
>  	int ret;
>  
> @@ -1190,9 +1190,9 @@ int drm_gem_vmap(struct drm_gem_object *obj, struct iosys_map *map)
>  
>  	return 0;
>  }
> -EXPORT_SYMBOL(drm_gem_vmap);
> +EXPORT_SYMBOL(drm_gem_vmap_locked);
>  
> -void drm_gem_vunmap(struct drm_gem_object *obj, struct iosys_map *map)
> +void drm_gem_vunmap_locked(struct drm_gem_object *obj, struct iosys_map *map)
>  {
>  	dma_resv_assert_held(obj->resv);
>  
> @@ -1205,27 +1205,27 @@ void drm_gem_vunmap(struct drm_gem_object *obj, struct iosys_map *map)
>  	/* Always set the mapping to NULL. Callers may rely on this. */
>  	iosys_map_clear(map);
>  }
> -EXPORT_SYMBOL(drm_gem_vunmap);
> +EXPORT_SYMBOL(drm_gem_vunmap_locked);
>  
> -int drm_gem_vmap_unlocked(struct drm_gem_object *obj, struct iosys_map *map)
> +int drm_gem_vmap(struct drm_gem_object *obj, struct iosys_map *map)
>  {
>  	int ret;
>  
>  	dma_resv_lock(obj->resv, NULL);
> -	ret = drm_gem_vmap(obj, map);
> +	ret = drm_gem_vmap_locked(obj, map);
>  	dma_resv_unlock(obj->resv);
>  
>  	return ret;
>  }
> -EXPORT_SYMBOL(drm_gem_vmap_unlocked);
> +EXPORT_SYMBOL(drm_gem_vmap);
>  
> -void drm_gem_vunmap_unlocked(struct drm_gem_object *obj, struct iosys_map *map)
> +void drm_gem_vunmap(struct drm_gem_object *obj, struct iosys_map *map)
>  {
>  	dma_resv_lock(obj->resv, NULL);
> -	drm_gem_vunmap(obj, map);
> +	drm_gem_vunmap_locked(obj, map);
>  	dma_resv_unlock(obj->resv);
>  }
> -EXPORT_SYMBOL(drm_gem_vunmap_unlocked);
> +EXPORT_SYMBOL(drm_gem_vunmap);
>  
>  /**
>   * drm_gem_lock_reservations - Sets up the ww context and acquires
> diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
> index 3bdb6ba37ff4..3808f47310bf 100644
> --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c
> +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
> @@ -362,7 +362,7 @@ int drm_gem_fb_vmap(struct drm_framebuffer *fb, struct iosys_map *map,
>  			ret = -EINVAL;
>  			goto err_drm_gem_vunmap;
>  		}
> -		ret = drm_gem_vmap_unlocked(obj, &map[i]);
> +		ret = drm_gem_vmap(obj, &map[i]);
>  		if (ret)
>  			goto err_drm_gem_vunmap;
>  	}
> @@ -384,7 +384,7 @@ int drm_gem_fb_vmap(struct drm_framebuffer *fb, struct iosys_map *map,
>  		obj = drm_gem_fb_get_obj(fb, i);
>  		if (!obj)
>  			continue;
> -		drm_gem_vunmap_unlocked(obj, &map[i]);
> +		drm_gem_vunmap(obj, &map[i]);
>  	}
>  	return ret;
>  }
> @@ -411,7 +411,7 @@ void drm_gem_fb_vunmap(struct drm_framebuffer *fb, struct iosys_map *map)
>  			continue;
>  		if (iosys_map_is_null(&map[i]))
>  			continue;
> -		drm_gem_vunmap_unlocked(obj, &map[i]);
> +		drm_gem_vunmap(obj, &map[i]);
>  	}
>  }
>  EXPORT_SYMBOL(drm_gem_fb_vunmap);
> diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
> index ba12acd55139..243d9aa52881 100644
> --- a/drivers/gpu/drm/drm_internal.h
> +++ b/drivers/gpu/drm/drm_internal.h
> @@ -175,8 +175,8 @@ void drm_gem_print_info(struct drm_printer *p, unsigned int indent,
>  
>  int drm_gem_pin(struct drm_gem_object *obj);
>  void drm_gem_unpin(struct drm_gem_object *obj);
> -int drm_gem_vmap(struct drm_gem_object *obj, struct iosys_map *map);
> -void drm_gem_vunmap(struct drm_gem_object *obj, struct iosys_map *map);
> +int drm_gem_vmap_locked(struct drm_gem_object *obj, struct iosys_map *map);
> +void drm_gem_vunmap_locked(struct drm_gem_object *obj, struct iosys_map *map);
>  
>  /* drm_debugfs.c drm_debugfs_crc.c */
>  #if defined(CONFIG_DEBUG_FS)
> diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
> index 63b709a67471..57ac5623f09a 100644
> --- a/drivers/gpu/drm/drm_prime.c
> +++ b/drivers/gpu/drm/drm_prime.c
> @@ -682,7 +682,7 @@ int drm_gem_dmabuf_vmap(struct dma_buf *dma_buf, struct iosys_map *map)
>  {
>  	struct drm_gem_object *obj = dma_buf->priv;
>  
> -	return drm_gem_vmap(obj, map);
> +	return drm_gem_vmap_locked(obj, map);
>  }
>  EXPORT_SYMBOL(drm_gem_dmabuf_vmap);
>  
> @@ -698,7 +698,7 @@ void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, struct iosys_map *map)
>  {
>  	struct drm_gem_object *obj = dma_buf->priv;
>  
> -	drm_gem_vunmap(obj, map);
> +	drm_gem_vunmap_locked(obj, map);
>  }
>  EXPORT_SYMBOL(drm_gem_dmabuf_vunmap);
>  
> diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c
> index ffd91a5ee299..843487128544 100644
> --- a/drivers/gpu/drm/lima/lima_sched.c
> +++ b/drivers/gpu/drm/lima/lima_sched.c
> @@ -371,7 +371,7 @@ static void lima_sched_build_error_task_list(struct lima_sched_task *task)
>  		} else {
>  			buffer_chunk->size = lima_bo_size(bo);
>  
> -			ret = drm_gem_vmap_unlocked(&bo->base.base, &map);
> +			ret = drm_gem_vmap(&bo->base.base, &map);
>  			if (ret) {
>  				kvfree(et);
>  				goto out;
> @@ -379,7 +379,7 @@ static void lima_sched_build_error_task_list(struct lima_sched_task *task)
>  
>  			memcpy(buffer_chunk + 1, map.vaddr, buffer_chunk->size);
>  
> -			drm_gem_vunmap_unlocked(&bo->base.base, &map);
> +			drm_gem_vunmap(&bo->base.base, &map);
>  		}
>  
>  		buffer_chunk = (void *)(buffer_chunk + 1) + buffer_chunk->size;
> diff --git a/drivers/gpu/drm/panfrost/panfrost_dump.c b/drivers/gpu/drm/panfrost/panfrost_dump.c
> index e7942ac449c6..0f30bbea9895 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_dump.c
> +++ b/drivers/gpu/drm/panfrost/panfrost_dump.c
> @@ -209,7 +209,7 @@ void panfrost_core_dump(struct panfrost_job *job)
>  			goto dump_header;
>  		}
>  
> -		ret = drm_gem_vmap_unlocked(&bo->base.base, &map);
> +		ret = drm_gem_vmap(&bo->base.base, &map);
>  		if (ret) {
>  			dev_err(pfdev->dev, "Panfrost Dump: couldn't map Buffer Object\n");
>  			iter.hdr->bomap.valid = 0;
> @@ -236,7 +236,7 @@ void panfrost_core_dump(struct panfrost_job *job)
>  		vaddr = map.vaddr;
>  		memcpy(iter.data, vaddr, bo->base.base.size);
>  
> -		drm_gem_vunmap_unlocked(&bo->base.base, &map);
> +		drm_gem_vunmap(&bo->base.base, &map);
>  
>  		iter.hdr->bomap.valid = 1;
>  
> diff --git a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
> index ba9b6e2b2636..52befead08c6 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
> +++ b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
> @@ -106,7 +106,7 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev,
>  		goto err_close_bo;
>  	}
>  
> -	ret = drm_gem_vmap_unlocked(&bo->base, &map);
> +	ret = drm_gem_vmap(&bo->base, &map);
>  	if (ret)
>  		goto err_put_mapping;
>  	perfcnt->buf = map.vaddr;
> @@ -165,7 +165,7 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev,
>  	return 0;
>  
>  err_vunmap:
> -	drm_gem_vunmap_unlocked(&bo->base, &map);
> +	drm_gem_vunmap(&bo->base, &map);
>  err_put_mapping:
>  	panfrost_gem_mapping_put(perfcnt->mapping);
>  err_close_bo:
> @@ -195,7 +195,7 @@ static int panfrost_perfcnt_disable_locked(struct panfrost_device *pfdev,
>  		  GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_OFF));
>  
>  	perfcnt->user = NULL;
> -	drm_gem_vunmap_unlocked(&perfcnt->mapping->obj->base.base, &map);
> +	drm_gem_vunmap(&perfcnt->mapping->obj->base.base, &map);
>  	perfcnt->buf = NULL;
>  	panfrost_gem_close(&perfcnt->mapping->obj->base.base, file_priv);
>  	panfrost_mmu_as_put(pfdev, perfcnt->mapping->mmu);
> diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
> index c0b13c43b459..f338f8cfacf7 100644
> --- a/include/drm/drm_gem.h
> +++ b/include/drm/drm_gem.h
> @@ -518,8 +518,8 @@ struct page **drm_gem_get_pages(struct drm_gem_object *obj);
>  void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages,
>  		bool dirty, bool accessed);
>  
> -int drm_gem_vmap_unlocked(struct drm_gem_object *obj, struct iosys_map *map);
> -void drm_gem_vunmap_unlocked(struct drm_gem_object *obj, struct iosys_map *map);
> +int drm_gem_vmap(struct drm_gem_object *obj, struct iosys_map *map);
> +void drm_gem_vunmap(struct drm_gem_object *obj, struct iosys_map *map);
>  
>  int drm_gem_objects_lookup(struct drm_file *filp, void __user *bo_handles,
>  			   int count, struct drm_gem_object ***objs_out);


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 04/23] drm/gem: Add _locked postfix to functions that have unlocked counterpart
  2023-08-27 17:54 ` [PATCH v15 04/23] drm/gem: Add _locked postfix to functions that have unlocked counterpart Dmitry Osipenko
@ 2023-08-28 11:25   ` Boris Brezillon
  0 siblings, 0 replies; 53+ messages in thread
From: Boris Brezillon @ 2023-08-28 11:25 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Emma Anholt, Melissa Wen, Will Deacon, Peter Zijlstra,
	Boqun Feng, Mark Rutland, dri-devel, linux-kernel, kernel,
	virtualization, intel-gfx

On Sun, 27 Aug 2023 20:54:30 +0300
Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:

> Add _locked postfix to drm_gem functions that have unlocked counterpart
> functions to make GEM functions naming more consistent and intuitive in
> regards to the locking requirements.
> 
> Suggested-by: Boris Brezillon <boris.brezillon@collabora.com>
> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>

Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>

> ---
>  drivers/gpu/drm/drm_gem.c | 6 +++---
>  include/drm/drm_gem.h     | 2 +-
>  2 files changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
> index fae5832bb0bd..8c0268944199 100644
> --- a/drivers/gpu/drm/drm_gem.c
> +++ b/drivers/gpu/drm/drm_gem.c
> @@ -1488,10 +1488,10 @@ drm_gem_lru_scan(struct drm_gem_lru *lru,
>  EXPORT_SYMBOL(drm_gem_lru_scan);
>  
>  /**
> - * drm_gem_evict - helper to evict backing pages for a GEM object
> + * drm_gem_evict_locked - helper to evict backing pages for a GEM object
>   * @obj: obj in question
>   */
> -int drm_gem_evict(struct drm_gem_object *obj)
> +int drm_gem_evict_locked(struct drm_gem_object *obj)
>  {
>  	dma_resv_assert_held(obj->resv);
>  
> @@ -1503,4 +1503,4 @@ int drm_gem_evict(struct drm_gem_object *obj)
>  
>  	return 0;
>  }
> -EXPORT_SYMBOL(drm_gem_evict);
> +EXPORT_SYMBOL(drm_gem_evict_locked);
> diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
> index f338f8cfacf7..e78e6d817451 100644
> --- a/include/drm/drm_gem.h
> +++ b/include/drm/drm_gem.h
> @@ -542,7 +542,7 @@ unsigned long drm_gem_lru_scan(struct drm_gem_lru *lru,
>  			       unsigned long *remaining,
>  			       bool (*shrink)(struct drm_gem_object *obj));
>  
> -int drm_gem_evict(struct drm_gem_object *obj);
> +int drm_gem_evict_locked(struct drm_gem_object *obj);
>  
>  #ifdef CONFIG_LOCKDEP
>  /**


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 08/23] drm/shmem-helper: Refactor locked/unlocked functions
  2023-08-27 17:54 ` [PATCH v15 08/23] drm/shmem-helper: Refactor locked/unlocked functions Dmitry Osipenko
@ 2023-08-28 11:28   ` Boris Brezillon
  0 siblings, 0 replies; 53+ messages in thread
From: Boris Brezillon @ 2023-08-28 11:28 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Emma Anholt, Melissa Wen, Will Deacon, Peter Zijlstra,
	Boqun Feng, Mark Rutland, dri-devel, linux-kernel, kernel,
	virtualization, intel-gfx

On Sun, 27 Aug 2023 20:54:34 +0300
Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:

> Add locked and remove unlocked postfixes from drm-shmem function names,
> making names consistent with the drm/gem core code.
> 
> Suggested-by: Boris Brezillon <boris.brezillon@collabora.com>
> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>

Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>

> ---
>  drivers/gpu/drm/drm_gem_shmem_helper.c        | 64 +++++++++----------
>  drivers/gpu/drm/lima/lima_gem.c               |  8 +--
>  drivers/gpu/drm/panfrost/panfrost_drv.c       |  2 +-
>  drivers/gpu/drm/panfrost/panfrost_gem.c       |  6 +-
>  .../gpu/drm/panfrost/panfrost_gem_shrinker.c  |  2 +-
>  drivers/gpu/drm/panfrost/panfrost_mmu.c       |  2 +-
>  drivers/gpu/drm/v3d/v3d_bo.c                  |  4 +-
>  drivers/gpu/drm/virtio/virtgpu_object.c       |  4 +-
>  include/drm/drm_gem_shmem_helper.h            | 36 +++++------
>  9 files changed, 64 insertions(+), 64 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
> index 575704f38808..f053dc511508 100644
> --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
> +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
> @@ -43,8 +43,8 @@ static const struct drm_gem_object_funcs drm_gem_shmem_funcs = {
>  	.pin = drm_gem_shmem_object_pin,
>  	.unpin = drm_gem_shmem_object_unpin,
>  	.get_sg_table = drm_gem_shmem_object_get_sg_table,
> -	.vmap = drm_gem_shmem_object_vmap,
> -	.vunmap = drm_gem_shmem_object_vunmap,
> +	.vmap = drm_gem_shmem_object_vmap_locked,
> +	.vunmap = drm_gem_shmem_object_vunmap_locked,
>  	.mmap = drm_gem_shmem_object_mmap,
>  	.vm_ops = &drm_gem_shmem_vm_ops,
>  };
> @@ -153,7 +153,7 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
>  			kfree(shmem->sgt);
>  		}
>  		if (shmem->got_sgt)
> -			drm_gem_shmem_put_pages(shmem);
> +			drm_gem_shmem_put_pages_locked(shmem);
>  
>  		drm_WARN_ON(obj->dev, shmem->pages_use_count);
>  
> @@ -165,7 +165,7 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
>  }
>  EXPORT_SYMBOL_GPL(drm_gem_shmem_free);
>  
> -static int drm_gem_shmem_get_pages(struct drm_gem_shmem_object *shmem)
> +static int drm_gem_shmem_get_pages_locked(struct drm_gem_shmem_object *shmem)
>  {
>  	struct drm_gem_object *obj = &shmem->base;
>  	struct page **pages;
> @@ -199,12 +199,12 @@ static int drm_gem_shmem_get_pages(struct drm_gem_shmem_object *shmem)
>  }
>  
>  /*
> - * drm_gem_shmem_put_pages - Decrease use count on the backing pages for a shmem GEM object
> + * drm_gem_shmem_put_pages_locked - Decrease use count on the backing pages for a shmem GEM object
>   * @shmem: shmem GEM object
>   *
>   * This function decreases the use count and puts the backing pages when use drops to zero.
>   */
> -void drm_gem_shmem_put_pages(struct drm_gem_shmem_object *shmem)
> +void drm_gem_shmem_put_pages_locked(struct drm_gem_shmem_object *shmem)
>  {
>  	struct drm_gem_object *obj = &shmem->base;
>  
> @@ -226,7 +226,7 @@ void drm_gem_shmem_put_pages(struct drm_gem_shmem_object *shmem)
>  			  shmem->pages_mark_accessed_on_put);
>  	shmem->pages = NULL;
>  }
> -EXPORT_SYMBOL_GPL(drm_gem_shmem_put_pages);
> +EXPORT_SYMBOL_GPL(drm_gem_shmem_put_pages_locked);
>  
>  static int drm_gem_shmem_pin_locked(struct drm_gem_shmem_object *shmem)
>  {
> @@ -234,7 +234,7 @@ static int drm_gem_shmem_pin_locked(struct drm_gem_shmem_object *shmem)
>  
>  	dma_resv_assert_held(shmem->base.resv);
>  
> -	ret = drm_gem_shmem_get_pages(shmem);
> +	ret = drm_gem_shmem_get_pages_locked(shmem);
>  
>  	return ret;
>  }
> @@ -243,7 +243,7 @@ static void drm_gem_shmem_unpin_locked(struct drm_gem_shmem_object *shmem)
>  {
>  	dma_resv_assert_held(shmem->base.resv);
>  
> -	drm_gem_shmem_put_pages(shmem);
> +	drm_gem_shmem_put_pages_locked(shmem);
>  }
>  
>  /**
> @@ -293,7 +293,7 @@ void drm_gem_shmem_unpin(struct drm_gem_shmem_object *shmem)
>  EXPORT_SYMBOL_GPL(drm_gem_shmem_unpin);
>  
>  /*
> - * drm_gem_shmem_vmap - Create a virtual mapping for a shmem GEM object
> + * drm_gem_shmem_vmap_locked - Create a virtual mapping for a shmem GEM object
>   * @shmem: shmem GEM object
>   * @map: Returns the kernel virtual address of the SHMEM GEM object's backing
>   *       store.
> @@ -302,13 +302,13 @@ EXPORT_SYMBOL_GPL(drm_gem_shmem_unpin);
>   * exists for the buffer backing the shmem GEM object. It hides the differences
>   * between dma-buf imported and natively allocated objects.
>   *
> - * Acquired mappings should be cleaned up by calling drm_gem_shmem_vunmap().
> + * Acquired mappings should be cleaned up by calling drm_gem_shmem_vunmap_locked().
>   *
>   * Returns:
>   * 0 on success or a negative error code on failure.
>   */
> -int drm_gem_shmem_vmap(struct drm_gem_shmem_object *shmem,
> -		       struct iosys_map *map)
> +int drm_gem_shmem_vmap_locked(struct drm_gem_shmem_object *shmem,
> +			      struct iosys_map *map)
>  {
>  	struct drm_gem_object *obj = &shmem->base;
>  	int ret = 0;
> @@ -331,7 +331,7 @@ int drm_gem_shmem_vmap(struct drm_gem_shmem_object *shmem,
>  			return 0;
>  		}
>  
> -		ret = drm_gem_shmem_get_pages(shmem);
> +		ret = drm_gem_shmem_get_pages_locked(shmem);
>  		if (ret)
>  			goto err_zero_use;
>  
> @@ -354,28 +354,28 @@ int drm_gem_shmem_vmap(struct drm_gem_shmem_object *shmem,
>  
>  err_put_pages:
>  	if (!obj->import_attach)
> -		drm_gem_shmem_put_pages(shmem);
> +		drm_gem_shmem_put_pages_locked(shmem);
>  err_zero_use:
>  	shmem->vmap_use_count = 0;
>  
>  	return ret;
>  }
> -EXPORT_SYMBOL_GPL(drm_gem_shmem_vmap);
> +EXPORT_SYMBOL_GPL(drm_gem_shmem_vmap_locked);
>  
>  /*
> - * drm_gem_shmem_vunmap - Unmap a virtual mapping for a shmem GEM object
> + * drm_gem_shmem_vunmap_locked - Unmap a virtual mapping for a shmem GEM object
>   * @shmem: shmem GEM object
>   * @map: Kernel virtual address where the SHMEM GEM object was mapped
>   *
>   * This function cleans up a kernel virtual address mapping acquired by
> - * drm_gem_shmem_vmap(). The mapping is only removed when the use count drops to
> - * zero.
> + * drm_gem_shmem_vmap_locked(). The mapping is only removed when the use count
> + * drops to zero.
>   *
>   * This function hides the differences between dma-buf imported and natively
>   * allocated objects.
>   */
> -void drm_gem_shmem_vunmap(struct drm_gem_shmem_object *shmem,
> -			  struct iosys_map *map)
> +void drm_gem_shmem_vunmap_locked(struct drm_gem_shmem_object *shmem,
> +				 struct iosys_map *map)
>  {
>  	struct drm_gem_object *obj = &shmem->base;
>  
> @@ -391,12 +391,12 @@ void drm_gem_shmem_vunmap(struct drm_gem_shmem_object *shmem,
>  			return;
>  
>  		vunmap(shmem->vaddr);
> -		drm_gem_shmem_put_pages(shmem);
> +		drm_gem_shmem_put_pages_locked(shmem);
>  	}
>  
>  	shmem->vaddr = NULL;
>  }
> -EXPORT_SYMBOL_GPL(drm_gem_shmem_vunmap);
> +EXPORT_SYMBOL_GPL(drm_gem_shmem_vunmap_locked);
>  
>  static int
>  drm_gem_shmem_create_with_handle(struct drm_file *file_priv,
> @@ -424,7 +424,7 @@ drm_gem_shmem_create_with_handle(struct drm_file *file_priv,
>  /* Update madvise status, returns true if not purged, else
>   * false or -errno.
>   */
> -int drm_gem_shmem_madvise(struct drm_gem_shmem_object *shmem, int madv)
> +int drm_gem_shmem_madvise_locked(struct drm_gem_shmem_object *shmem, int madv)
>  {
>  	dma_resv_assert_held(shmem->base.resv);
>  
> @@ -435,9 +435,9 @@ int drm_gem_shmem_madvise(struct drm_gem_shmem_object *shmem, int madv)
>  
>  	return (madv >= 0);
>  }
> -EXPORT_SYMBOL_GPL(drm_gem_shmem_madvise);
> +EXPORT_SYMBOL_GPL(drm_gem_shmem_madvise_locked);
>  
> -void drm_gem_shmem_purge(struct drm_gem_shmem_object *shmem)
> +void drm_gem_shmem_purge_locked(struct drm_gem_shmem_object *shmem)
>  {
>  	struct drm_gem_object *obj = &shmem->base;
>  	struct drm_device *dev = obj->dev;
> @@ -451,7 +451,7 @@ void drm_gem_shmem_purge(struct drm_gem_shmem_object *shmem)
>  	kfree(shmem->sgt);
>  	shmem->sgt = NULL;
>  
> -	drm_gem_shmem_put_pages(shmem);
> +	drm_gem_shmem_put_pages_locked(shmem);
>  
>  	shmem->madv = -1;
>  
> @@ -467,7 +467,7 @@ void drm_gem_shmem_purge(struct drm_gem_shmem_object *shmem)
>  
>  	invalidate_mapping_pages(file_inode(obj->filp)->i_mapping, 0, (loff_t)-1);
>  }
> -EXPORT_SYMBOL_GPL(drm_gem_shmem_purge);
> +EXPORT_SYMBOL_GPL(drm_gem_shmem_purge_locked);
>  
>  /**
>   * drm_gem_shmem_dumb_create - Create a dumb shmem buffer object
> @@ -564,7 +564,7 @@ static void drm_gem_shmem_vm_close(struct vm_area_struct *vma)
>  	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
>  
>  	dma_resv_lock(shmem->base.resv, NULL);
> -	drm_gem_shmem_put_pages(shmem);
> +	drm_gem_shmem_put_pages_locked(shmem);
>  	dma_resv_unlock(shmem->base.resv);
>  
>  	drm_gem_vm_close(vma);
> @@ -605,7 +605,7 @@ int drm_gem_shmem_mmap(struct drm_gem_shmem_object *shmem, struct vm_area_struct
>  	}
>  
>  	dma_resv_lock(shmem->base.resv, NULL);
> -	ret = drm_gem_shmem_get_pages(shmem);
> +	ret = drm_gem_shmem_get_pages_locked(shmem);
>  	dma_resv_unlock(shmem->base.resv);
>  
>  	if (ret)
> @@ -673,7 +673,7 @@ static struct sg_table *drm_gem_shmem_get_pages_sgt_locked(struct drm_gem_shmem_
>  
>  	drm_WARN_ON(obj->dev, obj->import_attach);
>  
> -	ret = drm_gem_shmem_get_pages(shmem);
> +	ret = drm_gem_shmem_get_pages_locked(shmem);
>  	if (ret)
>  		return ERR_PTR(ret);
>  
> @@ -696,7 +696,7 @@ static struct sg_table *drm_gem_shmem_get_pages_sgt_locked(struct drm_gem_shmem_
>  	sg_free_table(sgt);
>  	kfree(sgt);
>  err_put_pages:
> -	drm_gem_shmem_put_pages(shmem);
> +	drm_gem_shmem_put_pages_locked(shmem);
>  	return ERR_PTR(ret);
>  }
>  
> diff --git a/drivers/gpu/drm/lima/lima_gem.c b/drivers/gpu/drm/lima/lima_gem.c
> index 28602302c281..7d74c71f5558 100644
> --- a/drivers/gpu/drm/lima/lima_gem.c
> +++ b/drivers/gpu/drm/lima/lima_gem.c
> @@ -181,7 +181,7 @@ static int lima_gem_pin(struct drm_gem_object *obj)
>  	if (bo->heap_size)
>  		return -EINVAL;
>  
> -	return drm_gem_shmem_pin(&bo->base);
> +	return drm_gem_shmem_object_pin(obj);
>  }
>  
>  static int lima_gem_vmap(struct drm_gem_object *obj, struct iosys_map *map)
> @@ -191,7 +191,7 @@ static int lima_gem_vmap(struct drm_gem_object *obj, struct iosys_map *map)
>  	if (bo->heap_size)
>  		return -EINVAL;
>  
> -	return drm_gem_shmem_vmap(&bo->base, map);
> +	return drm_gem_shmem_object_vmap_locked(obj, map);
>  }
>  
>  static int lima_gem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
> @@ -201,7 +201,7 @@ static int lima_gem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
>  	if (bo->heap_size)
>  		return -EINVAL;
>  
> -	return drm_gem_shmem_mmap(&bo->base, vma);
> +	return drm_gem_shmem_object_mmap(obj, vma);
>  }
>  
>  static const struct drm_gem_object_funcs lima_gem_funcs = {
> @@ -213,7 +213,7 @@ static const struct drm_gem_object_funcs lima_gem_funcs = {
>  	.unpin = drm_gem_shmem_object_unpin,
>  	.get_sg_table = drm_gem_shmem_object_get_sg_table,
>  	.vmap = lima_gem_vmap,
> -	.vunmap = drm_gem_shmem_object_vunmap,
> +	.vunmap = drm_gem_shmem_object_vunmap_locked,
>  	.mmap = lima_gem_mmap,
>  	.vm_ops = &drm_gem_shmem_vm_ops,
>  };
> diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c
> index a2ab99698ca8..175443eacead 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_drv.c
> +++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
> @@ -436,7 +436,7 @@ static int panfrost_ioctl_madvise(struct drm_device *dev, void *data,
>  		}
>  	}
>  
> -	args->retained = drm_gem_shmem_madvise(&bo->base, args->madv);
> +	args->retained = drm_gem_shmem_madvise_locked(&bo->base, args->madv);
>  
>  	if (args->retained) {
>  		if (args->madv == PANFROST_MADV_DONTNEED)
> diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.c b/drivers/gpu/drm/panfrost/panfrost_gem.c
> index 3c812fbd126f..59c8c73c6a59 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_gem.c
> +++ b/drivers/gpu/drm/panfrost/panfrost_gem.c
> @@ -192,7 +192,7 @@ static int panfrost_gem_pin(struct drm_gem_object *obj)
>  	if (bo->is_heap)
>  		return -EINVAL;
>  
> -	return drm_gem_shmem_pin(&bo->base);
> +	return drm_gem_shmem_object_pin(obj);
>  }
>  
>  static const struct drm_gem_object_funcs panfrost_gem_funcs = {
> @@ -203,8 +203,8 @@ static const struct drm_gem_object_funcs panfrost_gem_funcs = {
>  	.pin = panfrost_gem_pin,
>  	.unpin = drm_gem_shmem_object_unpin,
>  	.get_sg_table = drm_gem_shmem_object_get_sg_table,
> -	.vmap = drm_gem_shmem_object_vmap,
> -	.vunmap = drm_gem_shmem_object_vunmap,
> +	.vmap = drm_gem_shmem_object_vmap_locked,
> +	.vunmap = drm_gem_shmem_object_vunmap_locked,
>  	.mmap = drm_gem_shmem_object_mmap,
>  	.vm_ops = &drm_gem_shmem_vm_ops,
>  };
> diff --git a/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c b/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
> index 6a71a2555f85..72193bd734e1 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
> +++ b/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
> @@ -52,7 +52,7 @@ static bool panfrost_gem_purge(struct drm_gem_object *obj)
>  		goto unlock_mappings;
>  
>  	panfrost_gem_teardown_mappings_locked(bo);
> -	drm_gem_shmem_purge(&bo->base);
> +	drm_gem_shmem_purge_locked(&bo->base);
>  	ret = true;
>  
>  	dma_resv_unlock(shmem->base.resv);
> diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c
> index c0123d09f699..7771769f0ce0 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_mmu.c
> +++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c
> @@ -535,7 +535,7 @@ static int panfrost_mmu_map_fault_addr(struct panfrost_device *pfdev, int as,
>  err_map:
>  	sg_free_table(sgt);
>  err_pages:
> -	drm_gem_shmem_put_pages(&bo->base);
> +	drm_gem_shmem_put_pages_locked(&bo->base);
>  err_unlock:
>  	dma_resv_unlock(obj->resv);
>  err_bo:
> diff --git a/drivers/gpu/drm/v3d/v3d_bo.c b/drivers/gpu/drm/v3d/v3d_bo.c
> index 70c1095d6eec..6a0e7b6177d5 100644
> --- a/drivers/gpu/drm/v3d/v3d_bo.c
> +++ b/drivers/gpu/drm/v3d/v3d_bo.c
> @@ -58,8 +58,8 @@ static const struct drm_gem_object_funcs v3d_gem_funcs = {
>  	.pin = drm_gem_shmem_object_pin,
>  	.unpin = drm_gem_shmem_object_unpin,
>  	.get_sg_table = drm_gem_shmem_object_get_sg_table,
> -	.vmap = drm_gem_shmem_object_vmap,
> -	.vunmap = drm_gem_shmem_object_vunmap,
> +	.vmap = drm_gem_shmem_object_vmap_locked,
> +	.vunmap = drm_gem_shmem_object_vunmap_locked,
>  	.mmap = drm_gem_shmem_object_mmap,
>  	.vm_ops = &drm_gem_shmem_vm_ops,
>  };
> diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c b/drivers/gpu/drm/virtio/virtgpu_object.c
> index 343b13428125..97020ed56b81 100644
> --- a/drivers/gpu/drm/virtio/virtgpu_object.c
> +++ b/drivers/gpu/drm/virtio/virtgpu_object.c
> @@ -106,8 +106,8 @@ static const struct drm_gem_object_funcs virtio_gpu_shmem_funcs = {
>  	.pin = drm_gem_shmem_object_pin,
>  	.unpin = drm_gem_shmem_object_unpin,
>  	.get_sg_table = drm_gem_shmem_object_get_sg_table,
> -	.vmap = drm_gem_shmem_object_vmap,
> -	.vunmap = drm_gem_shmem_object_vunmap,
> +	.vmap = drm_gem_shmem_object_vmap_locked,
> +	.vunmap = drm_gem_shmem_object_vunmap_locked,
>  	.mmap = drm_gem_shmem_object_mmap,
>  	.vm_ops = &drm_gem_shmem_vm_ops,
>  };
> diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h
> index f87124629bb5..ec2d8b24e3cf 100644
> --- a/include/drm/drm_gem_shmem_helper.h
> +++ b/include/drm/drm_gem_shmem_helper.h
> @@ -113,16 +113,16 @@ struct drm_gem_shmem_object {
>  struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size);
>  void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem);
>  
> -void drm_gem_shmem_put_pages(struct drm_gem_shmem_object *shmem);
> +void drm_gem_shmem_put_pages_locked(struct drm_gem_shmem_object *shmem);
>  int drm_gem_shmem_pin(struct drm_gem_shmem_object *shmem);
>  void drm_gem_shmem_unpin(struct drm_gem_shmem_object *shmem);
> -int drm_gem_shmem_vmap(struct drm_gem_shmem_object *shmem,
> -		       struct iosys_map *map);
> -void drm_gem_shmem_vunmap(struct drm_gem_shmem_object *shmem,
> -			  struct iosys_map *map);
> +int drm_gem_shmem_vmap_locked(struct drm_gem_shmem_object *shmem,
> +			      struct iosys_map *map);
> +void drm_gem_shmem_vunmap_locked(struct drm_gem_shmem_object *shmem,
> +				 struct iosys_map *map);
>  int drm_gem_shmem_mmap(struct drm_gem_shmem_object *shmem, struct vm_area_struct *vma);
>  
> -int drm_gem_shmem_madvise(struct drm_gem_shmem_object *shmem, int madv);
> +int drm_gem_shmem_madvise_locked(struct drm_gem_shmem_object *shmem, int madv);
>  
>  static inline bool drm_gem_shmem_is_purgeable(struct drm_gem_shmem_object *shmem)
>  {
> @@ -131,7 +131,7 @@ static inline bool drm_gem_shmem_is_purgeable(struct drm_gem_shmem_object *shmem
>  		!shmem->base.dma_buf && !shmem->base.import_attach;
>  }
>  
> -void drm_gem_shmem_purge(struct drm_gem_shmem_object *shmem);
> +void drm_gem_shmem_purge_locked(struct drm_gem_shmem_object *shmem);
>  
>  struct sg_table *drm_gem_shmem_get_sg_table(struct drm_gem_shmem_object *shmem);
>  struct sg_table *drm_gem_shmem_get_pages_sgt(struct drm_gem_shmem_object *shmem);
> @@ -222,22 +222,22 @@ static inline struct sg_table *drm_gem_shmem_object_get_sg_table(struct drm_gem_
>  }
>  
>  /*
> - * drm_gem_shmem_object_vmap - GEM object function for drm_gem_shmem_vmap()
> + * drm_gem_shmem_object_vmap_locked - GEM object function for drm_gem_shmem_vmap_locked()
>   * @obj: GEM object
>   * @map: Returns the kernel virtual address of the SHMEM GEM object's backing store.
>   *
> - * This function wraps drm_gem_shmem_vmap(). Drivers that employ the shmem helpers should
> - * use it as their &drm_gem_object_funcs.vmap handler.
> + * This function wraps drm_gem_shmem_vmap_locked(). Drivers that employ the shmem
> + * helpers should use it as their &drm_gem_object_funcs.vmap handler.
>   *
>   * Returns:
>   * 0 on success or a negative error code on failure.
>   */
> -static inline int drm_gem_shmem_object_vmap(struct drm_gem_object *obj,
> -					    struct iosys_map *map)
> +static inline int drm_gem_shmem_object_vmap_locked(struct drm_gem_object *obj,
> +						   struct iosys_map *map)
>  {
>  	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
>  
> -	return drm_gem_shmem_vmap(shmem, map);
> +	return drm_gem_shmem_vmap_locked(shmem, map);
>  }
>  
>  /*
> @@ -245,15 +245,15 @@ static inline int drm_gem_shmem_object_vmap(struct drm_gem_object *obj,
>   * @obj: GEM object
>   * @map: Kernel virtual address where the SHMEM GEM object was mapped
>   *
> - * This function wraps drm_gem_shmem_vunmap(). Drivers that employ the shmem helpers should
> - * use it as their &drm_gem_object_funcs.vunmap handler.
> + * This function wraps drm_gem_shmem_vunmap_locked(). Drivers that employ the shmem
> + * helpers should use it as their &drm_gem_object_funcs.vunmap handler.
>   */
> -static inline void drm_gem_shmem_object_vunmap(struct drm_gem_object *obj,
> -					       struct iosys_map *map)
> +static inline void drm_gem_shmem_object_vunmap_locked(struct drm_gem_object *obj,
> +						      struct iosys_map *map)
>  {
>  	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
>  
> -	drm_gem_shmem_vunmap(shmem, map);
> +	drm_gem_shmem_vunmap_locked(shmem, map);
>  }
>  
>  /**


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 09/23] drm/shmem-helper: Remove obsoleted is_iomem test
  2023-08-27 17:54 ` [PATCH v15 09/23] drm/shmem-helper: Remove obsoleted is_iomem test Dmitry Osipenko
@ 2023-08-28 11:29   ` Boris Brezillon
  0 siblings, 0 replies; 53+ messages in thread
From: Boris Brezillon @ 2023-08-28 11:29 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Emma Anholt, Melissa Wen, Will Deacon, Peter Zijlstra,
	Boqun Feng, Mark Rutland, dri-devel, linux-kernel, kernel,
	virtualization, intel-gfx

On Sun, 27 Aug 2023 20:54:35 +0300
Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:

> Everything that uses the mapped buffer should by agnostic to is_iomem.

						^be

> The only reason for the is_iomem test is that we're setting shmem->vaddr
> to the returned map->vaddr. Now that the shmem->vaddr code is gone, remove
> the obsoleted is_iomem test to clean up the code.
> 
> Suggested-by: Thomas Zimmermann <tzimmermann@suse.de>
> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
> ---
>  drivers/gpu/drm/drm_gem_shmem_helper.c | 6 ------
>  1 file changed, 6 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
> index f053dc511508..d545d3d227d7 100644
> --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
> +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
> @@ -315,12 +315,6 @@ int drm_gem_shmem_vmap_locked(struct drm_gem_shmem_object *shmem,
>  
>  	if (obj->import_attach) {
>  		ret = dma_buf_vmap(obj->import_attach->dmabuf, map);
> -		if (!ret) {
> -			if (drm_WARN_ON(obj->dev, map->is_iomem)) {
> -				dma_buf_vunmap(obj->import_attach->dmabuf, map);
> -				return -EIO;
> -			}
> -		}
>  	} else {
>  		pgprot_t prot = PAGE_KERNEL;
>  


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 12/23] drm/shmem-helper: Add and use pages_pin_count
  2023-08-27 17:54 ` [PATCH v15 12/23] drm/shmem-helper: Add and use pages_pin_count Dmitry Osipenko
  2023-08-28  9:38   ` Boris Brezillon
@ 2023-08-28 11:46   ` Boris Brezillon
  2023-08-29  2:30     ` Dmitry Osipenko
  1 sibling, 1 reply; 53+ messages in thread
From: Boris Brezillon @ 2023-08-28 11:46 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Emma Anholt, Melissa Wen, Will Deacon, Peter Zijlstra,
	Boqun Feng, Mark Rutland, dri-devel, linux-kernel, kernel,
	virtualization, intel-gfx

On Sun, 27 Aug 2023 20:54:38 +0300
Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:

> Add separate pages_pin_count for tracking of whether drm-shmem pages are
> moveable or not. With the addition of memory shrinker support to drm-shmem,
> the pages_use_count will no longer determine whether pages are hard-pinned
> in memory, but whether pages exit and are soft-pinned (and could be swapped
> out). The pages_pin_count > 1 will hard-pin pages in memory.
> 
> Suggested-by: Boris Brezillon <boris.brezillon@collabora.com>
> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
> ---
>  drivers/gpu/drm/drm_gem_shmem_helper.c | 22 +++++++++++++++++-----
>  include/drm/drm_gem_shmem_helper.h     | 10 ++++++++++
>  2 files changed, 27 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
> index d545d3d227d7..1a7e5c332fd8 100644
> --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
> +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
> @@ -234,14 +234,22 @@ static int drm_gem_shmem_pin_locked(struct drm_gem_shmem_object *shmem)
>  
>  	dma_resv_assert_held(shmem->base.resv);
>  
> +	if (kref_get_unless_zero(&shmem->pages_pin_count))
> +		return 0;
> +
>  	ret = drm_gem_shmem_get_pages_locked(shmem);
> +	if (!ret)
> +		kref_init(&shmem->pages_pin_count);
>  
>  	return ret;
>  }
>  
> -static void drm_gem_shmem_unpin_locked(struct drm_gem_shmem_object *shmem)
> +static void drm_gem_shmem_kref_unpin_pages(struct kref *kref)
>  {
> -	dma_resv_assert_held(shmem->base.resv);
> +	struct drm_gem_shmem_object *shmem;
> +
> +	shmem = container_of(kref, struct drm_gem_shmem_object,
> +			     pages_pin_count);
>  
>  	drm_gem_shmem_put_pages_locked(shmem);
>  }
> @@ -263,6 +271,9 @@ int drm_gem_shmem_pin(struct drm_gem_shmem_object *shmem)
>  
>  	drm_WARN_ON(obj->dev, obj->import_attach);
>  
> +	if (kref_get_unless_zero(&shmem->pages_pin_count))
> +		return 0;
> +
>  	ret = dma_resv_lock_interruptible(shmem->base.resv, NULL);
>  	if (ret)
>  		return ret;
> @@ -286,9 +297,10 @@ void drm_gem_shmem_unpin(struct drm_gem_shmem_object *shmem)
>  
>  	drm_WARN_ON(obj->dev, obj->import_attach);
>  
> -	dma_resv_lock(shmem->base.resv, NULL);
> -	drm_gem_shmem_unpin_locked(shmem);
> -	dma_resv_unlock(shmem->base.resv);
> +	if (kref_put_dma_resv(&shmem->pages_pin_count,
> +			      drm_gem_shmem_kref_unpin_pages,
> +			      obj->resv, NULL))
> +		dma_resv_unlock(obj->resv);
>  }
>  EXPORT_SYMBOL_GPL(drm_gem_shmem_unpin);
>  
> diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h
> index ec2d8b24e3cf..afb7cd671e2a 100644
> --- a/include/drm/drm_gem_shmem_helper.h
> +++ b/include/drm/drm_gem_shmem_helper.h
> @@ -39,6 +39,16 @@ struct drm_gem_shmem_object {
>  	 */
>  	unsigned int pages_use_count;
>  
> +	/**
> +	 * @pages_pin_count:
> +	 *
> +	 * Reference count on the pinned pages table.
> +	 * The pages allowed to be evicted and purged by memory
> +	 * shrinker only when the count is zero, otherwise pages
> +	 * are hard-pinned in memory.
> +	 */
> +	struct kref pages_pin_count;

I know it's tempting to use kref for the pages use/pin count, but I'm
wondering if we wouldn't be better using a refcount_t, which provides
overflow/underflow protection while still letting us control how we
want to handle the locking for 0 <-> 1 transitions. By doing that, we
avoid introducing core locking changes that might be more
controversial/longer to get accepted. Besides, I suspect the resulting
code (the one using a refcount_t) won't be more verbose/complicated (no
release functions needed if you don't use kref_put(), which makes
things closer to what we have right now).

> +
>  	/**
>  	 * @madv: State for madvise
>  	 *


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 00/23] Add generic memory shrinker to  VirtIO-GPU and Panfrost DRM drivers
  2023-08-27 17:54 [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Dmitry Osipenko
                   ` (22 preceding siblings ...)
  2023-08-27 17:54 ` [PATCH v15 23/23] drm/panfrost: Switch to generic memory shrinker Dmitry Osipenko
@ 2023-08-28 14:37 ` Helen Mae Koike Fornazier
  2023-08-28 15:24   ` Helen Mae Koike Fornazier
  23 siblings, 1 reply; 53+ messages in thread
From: Helen Mae Koike Fornazier @ 2023-08-28 14:37 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Boris Brezillon, Emma Anholt, Melissa Wen, Will Deacon,
	Peter Zijlstra, Boqun Feng, Mark Rutland, intel-gfx, kernel,
	linux-kernel, dri-devel, virtualization

On Sunday, August 27, 2023 14:54 -03, Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:

> This series:
> 
>   1. Adds common drm-shmem memory shrinker
>   2. Enables shrinker for VirtIO-GPU driver
>   3. Switches Panfrost driver to the common shrinker

Hi Dmitry, 

Would you mind testing with drm-ci? We virt-io tests there and it would be
really great to get your feedback of it.

https://cgit.freedesktop.org/drm/drm/log/?h=topic/drm-ci

You need to merge your changes with the above tree.
To configure it, you just need to have a tree on gitlab.freedesktop.org,
go to the settings and change the CI/CD configuration file from .gitlab-ci.yml
to drivers/gpu/drm/ci/gitlab-ci.yml, and you can start a pipeline
on your branch.

at the time of this writting, gitlab.freedesktop.org is under maintenance,
but it should be back soon.

Thank you!
Helen

> 
> Changelog:
> 
> v15:- Moved drm-shmem reference counters to use kref that allows to
>       optimize unlocked functions, like was suggested by Boris Brezillon.
> 
>     - Changed drm/gem/shmem function names to use _locked postfix and
>       dropped the _unlocked, making the naming scheme consistent across
>       DRM code, like was suggested by Boris Brezillon.
> 
>     - Added patch that fixes UAF in drm-shmem for drivers that import
>       dma-buf and then release buffer in the import error code path.
> 
>     - Added patch that makes drm-shmem use new flag for SGT's get_pages()
>       refcounting, preventing unbalanced refcounting when GEM is freed.
> 
>     - Fixed guest blob pinning in virtio-gpu driver that was missed
>       previously in the shrinker patch.
> 
>     - Moved VC4 and virtio-gpu drivers to use drm_gem_put() in
>       GEM-creation error code paths, which is now required by drm-shmem
>       and was missed in a previous patch versions.
> 
>     - Virtio-GPU now attaches shmem pages to host on first use and not
>       when BO is created. In older patch versions there was a potential
>       race condition in the BO creation code path where both
>       get_sgt()+object_attach() should've been made under same resv lock,
>       otherwise pages could be evicted before attachment is invoked.
> 
>     - Virtio-GPU and drm-shmem shrinker patches are split into smaller
>       ones.
> 
> v14:- All the prerequisite reservation locking patches landed upstream,
>       previously were a part of this series in v13 and older.
> 
>         https://lore.kernel.org/dri-devel/20230529223935.2672495-1-dmitry.osipenko@collabora.com/
> 
>     - Added patches to improve locked/unlocked function names, like was
>       suggested by Boris Brezillon for v13.
> 
>     - Made all exported drm-shmem symbols GPL, like was previously
>       discussed with Thomas Zimmermann on this series.
> 
>     - Improved virtio-gpu shrinker patch. Now it won't detach purged BO
>       when userspace closes GEM. Crosvm (and not qemu) checks res_id on
>       CMD_CTX_DETACH_RESOURCE and prints noisy error message if ID is
>       invalid, which wasn't noticed before.
> 
> v13:- Updated virtio-gpu shrinker patch to use drm_gem_shmem_object_pin()
>       directly instead of drm_gem_pin() and dropped patch that exported
>       drm_gem_pin() functions, like was requested by Thomas Zimmermann in
>       v12.
> 
> v12:- Fixed the "no previous prototype for function" warning reported by
>       kernel build bot for v11.
> 
>     - Fixed the missing reservation lock reported by Intel CI for VGEM
>       driver. Other drivers using drm-shmem were affected similarly to
>       VGEM. The problem was in the dma-buf attachment code path that led
>       to drm-shmem pinning function which assumed the held reservation lock
>       by drm_gem_pin(). In the past that code path was causing trouble for
>       i915 driver and we've changed the locking scheme for the attachment
>       code path in the dma-buf core to let exporters to handle the locking
>       themselves. After a closer investigation, I realized that my assumption
>       about testing of dma-buf export code path using Panfrost driver was
>       incorrect. Now I created additional local test to exrecise the Panfrost
>       export path. I also reproduced the issue reported by the Intel CI for
>       v10. It's all fixed now by making the drm_gem_shmem_pin() to take the
>       resv lock by itself.
> 
>     - Patches are based on top of drm-tip, CC'd intel-gfx CI for testing.
> 
> v11:- Rebased on a recent linux-next. Added new patch as a result:
> 
>         drm/shmem-helper: Export drm_gem_shmem_get_pages_sgt_locked()
> 
>         It's needed by the virtio-gpu driver to swap-in/unevict shmem
>         object, previously get_pages_sgt() didn't use locking.
> 
>     - Separated the "Add memory shrinker" patch into smaller parts to ease
>       the reviewing, as was requested by Thomas Zimmermann:
> 
>         drm/shmem-helper: Factor out pages alloc/release from
>           drm_gem_shmem_get/put_pages()
>         drm/shmem-helper: Add pages_pin_count field
>         drm/shmem-helper: Switch drm_gem_shmem_vmap/vunmap to use pin/unpin
>         drm/shmem-helper: Factor out unpinning part from drm_gem_shmem_purge()
> 
>     - Addessed the v10 review comments from Thomas Zimmermann: return errno
>       instead of bool, sort code alphabetically, rename function and etc
>       minor changes.
> 
>     - Added new patch to remove the "map->is_iomem" from drm-shmem, as
>       was suggested by Thomas Zimmermann.
> 
>     - Added acks and r-b's that were given to v10.
> 
> v10:- Was partially applied to misc-fixes/next.
> 
>       https://lore.kernel.org/dri-devel/6c16f303-81df-7ebe-85e9-51bb40a8b301@collabora.com/T/
> 
> Dmitry Osipenko (23):
>   drm/shmem-helper: Fix UAF in error path when freeing SGT of imported
>     GEM
>   drm/shmem-helper: Use flag for tracking page count bumped by
>     get_pages_sgt()
>   drm/gem: Change locked/unlocked postfix of drm_gem_v/unmap() function
>     names
>   drm/gem: Add _locked postfix to functions that have unlocked
>     counterpart
>   drm/v3d: Replace open-coded drm_gem_shmem_free() with
>     drm_gem_object_put()
>   drm/virtio: Replace drm_gem_shmem_free() with drm_gem_object_put()
>   drm/shmem-helper: Make all exported symbols GPL
>   drm/shmem-helper: Refactor locked/unlocked functions
>   drm/shmem-helper: Remove obsoleted is_iomem test
>   locking/refcount, kref: Add kref_put_ww_mutex()
>   dma-resv: Add kref_put_dma_resv()
>   drm/shmem-helper: Add and use pages_pin_count
>   drm/shmem-helper: Use kref for pages_use_count
>   drm/shmem-helper: Add and use lockless drm_gem_shmem_get_pages()
>   drm/shmem-helper: Switch drm_gem_shmem_vmap/vunmap to use pin/unpin
>   drm/shmem-helper: Use kref for vmap_use_count
>   drm/shmem-helper: Add and use drm_gem_shmem_resv_assert_held() helper
>   drm/shmem-helper: Add memory shrinker
>   drm/shmem-helper: Export drm_gem_shmem_get_pages_sgt_locked()
>   drm/virtio: Pin display framebuffer BO
>   drm/virtio: Attach shmem BOs dynamically
>   drm/virtio: Support memory shrinking
>   drm/panfrost: Switch to generic memory shrinker
> 
>  drivers/gpu/drm/drm_client.c                  |   6 +-
>  drivers/gpu/drm/drm_gem.c                     |  26 +-
>  drivers/gpu/drm/drm_gem_framebuffer_helper.c  |   6 +-
>  drivers/gpu/drm/drm_gem_shmem_helper.c        | 616 +++++++++++++++---
>  drivers/gpu/drm/drm_internal.h                |   4 +-
>  drivers/gpu/drm/drm_prime.c                   |   4 +-
>  drivers/gpu/drm/lima/lima_gem.c               |  11 +-
>  drivers/gpu/drm/lima/lima_sched.c             |   4 +-
>  drivers/gpu/drm/panfrost/Makefile             |   1 -
>  drivers/gpu/drm/panfrost/panfrost_device.h    |   4 -
>  drivers/gpu/drm/panfrost/panfrost_drv.c       |  29 +-
>  drivers/gpu/drm/panfrost/panfrost_dump.c      |   4 +-
>  drivers/gpu/drm/panfrost/panfrost_gem.c       |  36 +-
>  drivers/gpu/drm/panfrost/panfrost_gem.h       |   9 -
>  .../gpu/drm/panfrost/panfrost_gem_shrinker.c  | 122 ----
>  drivers/gpu/drm/panfrost/panfrost_job.c       |  18 +-
>  drivers/gpu/drm/panfrost/panfrost_mmu.c       |   4 +-
>  drivers/gpu/drm/panfrost/panfrost_perfcnt.c   |   6 +-
>  drivers/gpu/drm/v3d/v3d_bo.c                  |  26 +-
>  drivers/gpu/drm/virtio/virtgpu_drv.h          |  22 +-
>  drivers/gpu/drm/virtio/virtgpu_gem.c          |  80 +++
>  drivers/gpu/drm/virtio/virtgpu_ioctl.c        |  57 +-
>  drivers/gpu/drm/virtio/virtgpu_kms.c          |   8 +
>  drivers/gpu/drm/virtio/virtgpu_object.c       | 147 ++++-
>  drivers/gpu/drm/virtio/virtgpu_plane.c        |  17 +-
>  drivers/gpu/drm/virtio/virtgpu_submit.c       |  15 +-
>  drivers/gpu/drm/virtio/virtgpu_vq.c           |  40 ++
>  include/drm/drm_device.h                      |  10 +-
>  include/drm/drm_gem.h                         |   6 +-
>  include/drm/drm_gem_shmem_helper.h            | 141 +++-
>  include/linux/dma-resv.h                      |   9 +
>  include/linux/kref.h                          |  12 +
>  include/linux/refcount.h                      |   5 +
>  include/uapi/drm/virtgpu_drm.h                |  14 +
>  lib/refcount.c                                |  34 +
>  35 files changed, 1167 insertions(+), 386 deletions(-)
>  delete mode 100644 drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
> 
> -- 
> 2.41.0
>


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 00/23] Add generic memory shrinker to  VirtIO-GPU and Panfrost DRM drivers
  2023-08-28 14:37 ` [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Helen Mae Koike Fornazier
@ 2023-08-28 15:24   ` Helen Mae Koike Fornazier
  2023-08-29  2:36     ` Dmitry Osipenko
  0 siblings, 1 reply; 53+ messages in thread
From: Helen Mae Koike Fornazier @ 2023-08-28 15:24 UTC (permalink / raw)
  To: Helen Mae Koike Fornazier
  Cc: Dmitry Osipenko, Mark Rutland, Emma Anholt, Peter Zijlstra,
	dri-devel, Gurchetan Singh, Gerd Hoffmann, kernel, Will Deacon,
	Steven Price, intel-gfx, Boqun Feng, Maxime Ripard, Melissa Wen,
	virtualization, linux-kernel, Boris Brezillon, Qiang Yu,
	Thomas Zimmermann, Christian König

On Monday, August 28, 2023 11:37 -03, "Helen Mae Koike Fornazier" <helen.koike@collabora.com> wrote:

> On Sunday, August 27, 2023 14:54 -03, Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:
> 
> > This series:
> > 
> >   1. Adds common drm-shmem memory shrinker
> >   2. Enables shrinker for VirtIO-GPU driver
> >   3. Switches Panfrost driver to the common shrinker
> 
> Hi Dmitry, 
> 
> Would you mind testing with drm-ci? We virt-io tests there and it would be
> really great to get your feedback of it.
> 
> https://cgit.freedesktop.org/drm/drm/log/?h=topic/drm-ci

sorry, I forgot that you also need this patchset:
    https://lists.freedesktop.org/archives/dri-devel/2023-August/420063.html
to enable virtio_gpu test job.

Thanks again.
Helen

> 
> You need to merge your changes with the above tree.
> To configure it, you just need to have a tree on gitlab.freedesktop.org,
> go to the settings and change the CI/CD configuration file from .gitlab-ci.yml
> to drivers/gpu/drm/ci/gitlab-ci.yml, and you can start a pipeline
> on your branch.
> 
> at the time of this writting, gitlab.freedesktop.org is under maintenance,
> but it should be back soon.
> 
> Thank you!
> Helen
> 
> > 
> > Changelog:
> > 
> > v15:- Moved drm-shmem reference counters to use kref that allows to
> >       optimize unlocked functions, like was suggested by Boris Brezillon.
> > 
> >     - Changed drm/gem/shmem function names to use _locked postfix and
> >       dropped the _unlocked, making the naming scheme consistent across
> >       DRM code, like was suggested by Boris Brezillon.
> > 
> >     - Added patch that fixes UAF in drm-shmem for drivers that import
> >       dma-buf and then release buffer in the import error code path.
> > 
> >     - Added patch that makes drm-shmem use new flag for SGT's get_pages()
> >       refcounting, preventing unbalanced refcounting when GEM is freed.
> > 
> >     - Fixed guest blob pinning in virtio-gpu driver that was missed
> >       previously in the shrinker patch.
> > 
> >     - Moved VC4 and virtio-gpu drivers to use drm_gem_put() in
> >       GEM-creation error code paths, which is now required by drm-shmem
> >       and was missed in a previous patch versions.
> > 
> >     - Virtio-GPU now attaches shmem pages to host on first use and not
> >       when BO is created. In older patch versions there was a potential
> >       race condition in the BO creation code path where both
> >       get_sgt()+object_attach() should've been made under same resv lock,
> >       otherwise pages could be evicted before attachment is invoked.
> > 
> >     - Virtio-GPU and drm-shmem shrinker patches are split into smaller
> >       ones.
> > 
> > v14:- All the prerequisite reservation locking patches landed upstream,
> >       previously were a part of this series in v13 and older.
> > 
> >         https://lore.kernel.org/dri-devel/20230529223935.2672495-1-dmitry.osipenko@collabora.com/
> > 
> >     - Added patches to improve locked/unlocked function names, like was
> >       suggested by Boris Brezillon for v13.
> > 
> >     - Made all exported drm-shmem symbols GPL, like was previously
> >       discussed with Thomas Zimmermann on this series.
> > 
> >     - Improved virtio-gpu shrinker patch. Now it won't detach purged BO
> >       when userspace closes GEM. Crosvm (and not qemu) checks res_id on
> >       CMD_CTX_DETACH_RESOURCE and prints noisy error message if ID is
> >       invalid, which wasn't noticed before.
> > 
> > v13:- Updated virtio-gpu shrinker patch to use drm_gem_shmem_object_pin()
> >       directly instead of drm_gem_pin() and dropped patch that exported
> >       drm_gem_pin() functions, like was requested by Thomas Zimmermann in
> >       v12.
> > 
> > v12:- Fixed the "no previous prototype for function" warning reported by
> >       kernel build bot for v11.
> > 
> >     - Fixed the missing reservation lock reported by Intel CI for VGEM
> >       driver. Other drivers using drm-shmem were affected similarly to
> >       VGEM. The problem was in the dma-buf attachment code path that led
> >       to drm-shmem pinning function which assumed the held reservation lock
> >       by drm_gem_pin(). In the past that code path was causing trouble for
> >       i915 driver and we've changed the locking scheme for the attachment
> >       code path in the dma-buf core to let exporters to handle the locking
> >       themselves. After a closer investigation, I realized that my assumption
> >       about testing of dma-buf export code path using Panfrost driver was
> >       incorrect. Now I created additional local test to exrecise the Panfrost
> >       export path. I also reproduced the issue reported by the Intel CI for
> >       v10. It's all fixed now by making the drm_gem_shmem_pin() to take the
> >       resv lock by itself.
> > 
> >     - Patches are based on top of drm-tip, CC'd intel-gfx CI for testing.
> > 
> > v11:- Rebased on a recent linux-next. Added new patch as a result:
> > 
> >         drm/shmem-helper: Export drm_gem_shmem_get_pages_sgt_locked()
> > 
> >         It's needed by the virtio-gpu driver to swap-in/unevict shmem
> >         object, previously get_pages_sgt() didn't use locking.
> > 
> >     - Separated the "Add memory shrinker" patch into smaller parts to ease
> >       the reviewing, as was requested by Thomas Zimmermann:
> > 
> >         drm/shmem-helper: Factor out pages alloc/release from
> >           drm_gem_shmem_get/put_pages()
> >         drm/shmem-helper: Add pages_pin_count field
> >         drm/shmem-helper: Switch drm_gem_shmem_vmap/vunmap to use pin/unpin
> >         drm/shmem-helper: Factor out unpinning part from drm_gem_shmem_purge()
> > 
> >     - Addessed the v10 review comments from Thomas Zimmermann: return errno
> >       instead of bool, sort code alphabetically, rename function and etc
> >       minor changes.
> > 
> >     - Added new patch to remove the "map->is_iomem" from drm-shmem, as
> >       was suggested by Thomas Zimmermann.
> > 
> >     - Added acks and r-b's that were given to v10.
> > 
> > v10:- Was partially applied to misc-fixes/next.
> > 
> >       https://lore.kernel.org/dri-devel/6c16f303-81df-7ebe-85e9-51bb40a8b301@collabora.com/T/
> > 
> > Dmitry Osipenko (23):
> >   drm/shmem-helper: Fix UAF in error path when freeing SGT of imported
> >     GEM
> >   drm/shmem-helper: Use flag for tracking page count bumped by
> >     get_pages_sgt()
> >   drm/gem: Change locked/unlocked postfix of drm_gem_v/unmap() function
> >     names
> >   drm/gem: Add _locked postfix to functions that have unlocked
> >     counterpart
> >   drm/v3d: Replace open-coded drm_gem_shmem_free() with
> >     drm_gem_object_put()
> >   drm/virtio: Replace drm_gem_shmem_free() with drm_gem_object_put()
> >   drm/shmem-helper: Make all exported symbols GPL
> >   drm/shmem-helper: Refactor locked/unlocked functions
> >   drm/shmem-helper: Remove obsoleted is_iomem test
> >   locking/refcount, kref: Add kref_put_ww_mutex()
> >   dma-resv: Add kref_put_dma_resv()
> >   drm/shmem-helper: Add and use pages_pin_count
> >   drm/shmem-helper: Use kref for pages_use_count
> >   drm/shmem-helper: Add and use lockless drm_gem_shmem_get_pages()
> >   drm/shmem-helper: Switch drm_gem_shmem_vmap/vunmap to use pin/unpin
> >   drm/shmem-helper: Use kref for vmap_use_count
> >   drm/shmem-helper: Add and use drm_gem_shmem_resv_assert_held() helper
> >   drm/shmem-helper: Add memory shrinker
> >   drm/shmem-helper: Export drm_gem_shmem_get_pages_sgt_locked()
> >   drm/virtio: Pin display framebuffer BO
> >   drm/virtio: Attach shmem BOs dynamically
> >   drm/virtio: Support memory shrinking
> >   drm/panfrost: Switch to generic memory shrinker
> > 
> >  drivers/gpu/drm/drm_client.c                  |   6 +-
> >  drivers/gpu/drm/drm_gem.c                     |  26 +-
> >  drivers/gpu/drm/drm_gem_framebuffer_helper.c  |   6 +-
> >  drivers/gpu/drm/drm_gem_shmem_helper.c        | 616 +++++++++++++++---
> >  drivers/gpu/drm/drm_internal.h                |   4 +-
> >  drivers/gpu/drm/drm_prime.c                   |   4 +-
> >  drivers/gpu/drm/lima/lima_gem.c               |  11 +-
> >  drivers/gpu/drm/lima/lima_sched.c             |   4 +-
> >  drivers/gpu/drm/panfrost/Makefile             |   1 -
> >  drivers/gpu/drm/panfrost/panfrost_device.h    |   4 -
> >  drivers/gpu/drm/panfrost/panfrost_drv.c       |  29 +-
> >  drivers/gpu/drm/panfrost/panfrost_dump.c      |   4 +-
> >  drivers/gpu/drm/panfrost/panfrost_gem.c       |  36 +-
> >  drivers/gpu/drm/panfrost/panfrost_gem.h       |   9 -
> >  .../gpu/drm/panfrost/panfrost_gem_shrinker.c  | 122 ----
> >  drivers/gpu/drm/panfrost/panfrost_job.c       |  18 +-
> >  drivers/gpu/drm/panfrost/panfrost_mmu.c       |   4 +-
> >  drivers/gpu/drm/panfrost/panfrost_perfcnt.c   |   6 +-
> >  drivers/gpu/drm/v3d/v3d_bo.c                  |  26 +-
> >  drivers/gpu/drm/virtio/virtgpu_drv.h          |  22 +-
> >  drivers/gpu/drm/virtio/virtgpu_gem.c          |  80 +++
> >  drivers/gpu/drm/virtio/virtgpu_ioctl.c        |  57 +-
> >  drivers/gpu/drm/virtio/virtgpu_kms.c          |   8 +
> >  drivers/gpu/drm/virtio/virtgpu_object.c       | 147 ++++-
> >  drivers/gpu/drm/virtio/virtgpu_plane.c        |  17 +-
> >  drivers/gpu/drm/virtio/virtgpu_submit.c       |  15 +-
> >  drivers/gpu/drm/virtio/virtgpu_vq.c           |  40 ++
> >  include/drm/drm_device.h                      |  10 +-
> >  include/drm/drm_gem.h                         |   6 +-
> >  include/drm/drm_gem_shmem_helper.h            | 141 +++-
> >  include/linux/dma-resv.h                      |   9 +
> >  include/linux/kref.h                          |  12 +
> >  include/linux/refcount.h                      |   5 +
> >  include/uapi/drm/virtgpu_drm.h                |  14 +
> >  lib/refcount.c                                |  34 +
> >  35 files changed, 1167 insertions(+), 386 deletions(-)
> >  delete mode 100644 drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
> > 
> > -- 
> > 2.41.0
> >
>


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 10/23] locking/refcount, kref: Add kref_put_ww_mutex()
  2023-08-28  9:26   ` Boris Brezillon
@ 2023-08-29  2:28     ` Dmitry Osipenko
  0 siblings, 0 replies; 53+ messages in thread
From: Dmitry Osipenko @ 2023-08-29  2:28 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Emma Anholt, Melissa Wen, Will Deacon, Peter Zijlstra,
	Boqun Feng, Mark Rutland, dri-devel, linux-kernel, kernel,
	virtualization, intel-gfx

On 8/28/23 12:26, Boris Brezillon wrote:
> On Sun, 27 Aug 2023 20:54:36 +0300
> Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:
> 
>> Introduce kref_put_ww_mutex() helper that will handle the wait-wound
>> mutex auto-locking on kref_put(). This helper is wanted by DRM drivers
>> that extensively use dma-reservation locking which in turns uses ww-mutex.
>>
>> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
>> ---
>>  include/linux/kref.h     | 12 ++++++++++++
>>  include/linux/refcount.h |  5 +++++
>>  lib/refcount.c           | 34 ++++++++++++++++++++++++++++++++++
>>  3 files changed, 51 insertions(+)
>>
>> diff --git a/include/linux/kref.h b/include/linux/kref.h
>> index d32e21a2538c..b2d8dc6e9ae0 100644
>> --- a/include/linux/kref.h
>> +++ b/include/linux/kref.h
>> @@ -90,6 +90,18 @@ static inline int kref_put_lock(struct kref *kref,
>>  	return 0;
>>  }
>>  
>> +static inline int kref_put_ww_mutex(struct kref *kref,
>> +				    void (*release)(struct kref *kref),
>> +				    struct ww_mutex *lock,
>> +				    struct ww_acquire_ctx *ctx)
>> +{
>> +	if (refcount_dec_and_ww_mutex_lock(&kref->refcount, lock, ctx)) {
>> +		release(kref);
>> +		return 1;
>> +	}
>> +	return 0;
>> +}
>> +
>>  /**
>>   * kref_get_unless_zero - Increment refcount for object unless it is zero.
>>   * @kref: object.
>> diff --git a/include/linux/refcount.h b/include/linux/refcount.h
>> index a62fcca97486..be9ad272bc77 100644
>> --- a/include/linux/refcount.h
>> +++ b/include/linux/refcount.h
>> @@ -99,6 +99,8 @@
>>  #include <linux/spinlock_types.h>
>>  
>>  struct mutex;
>> +struct ww_mutex;
>> +struct ww_acquire_ctx;
>>  
>>  /**
>>   * typedef refcount_t - variant of atomic_t specialized for reference counts
>> @@ -366,4 +368,7 @@ extern __must_check bool refcount_dec_and_lock(refcount_t *r, spinlock_t *lock)
>>  extern __must_check bool refcount_dec_and_lock_irqsave(refcount_t *r,
>>  						       spinlock_t *lock,
>>  						       unsigned long *flags) __cond_acquires(lock);
>> +extern __must_check bool refcount_dec_and_ww_mutex_lock(refcount_t *r,
>> +							struct ww_mutex *lock,
>> +							struct ww_acquire_ctx *ctx) __cond_acquires(&lock->base);
>>  #endif /* _LINUX_REFCOUNT_H */
>> diff --git a/lib/refcount.c b/lib/refcount.c
>> index a207a8f22b3c..3f6fd0ceed02 100644
>> --- a/lib/refcount.c
>> +++ b/lib/refcount.c
>> @@ -6,6 +6,7 @@
>>  #include <linux/mutex.h>
>>  #include <linux/refcount.h>
>>  #include <linux/spinlock.h>
>> +#include <linux/ww_mutex.h>
>>  #include <linux/bug.h>
>>  
>>  #define REFCOUNT_WARN(str)	WARN_ONCE(1, "refcount_t: " str ".\n")
>> @@ -184,3 +185,36 @@ bool refcount_dec_and_lock_irqsave(refcount_t *r, spinlock_t *lock,
>>  	return true;
>>  }
>>  EXPORT_SYMBOL(refcount_dec_and_lock_irqsave);
>> +
>> +/**
>> + * refcount_dec_and_ww_mutex_lock - return holding ww-mutex if able to
>> + *                                  decrement refcount to 0
>> + * @r: the refcount
>> + * @lock: the ww-mutex to be locked
>> + * @ctx: wait-wound context
>> + *
>> + * Similar to atomic_dec_and_lock(), it will WARN on underflow and fail to
>> + * decrement when saturated at REFCOUNT_SATURATED.
>> + *
>> + * Provides release memory ordering, such that prior loads and stores are done
>> + * before, and provides a control dependency such that free() must come after.
>> + * See the comment on top.
>> + *
>> + * Return: true and hold ww-mutex lock if able to decrement refcount to 0,
>> + *         false otherwise
>> + */
>> +bool refcount_dec_and_ww_mutex_lock(refcount_t *r, struct ww_mutex *lock,
>> +				    struct ww_acquire_ctx *ctx)
>> +{
>> +	if (refcount_dec_not_one(r))
>> +		return false;
>> +
>> +	ww_mutex_lock(lock, ctx);
> 
> Unless I'm wrong, ww_mutex_lock() can return -EDEADLK when ctx !=
> NULL, in which case, the lock is not held when it returns. Question is,
> do we really have a use case for ctx != NULL in that kref_put_ww_mutex()
> path. If we need to acquire other ww_locks, this lock, and the other
> locks should have been acquired beforehand, and we can simply call
> kref_put() when we want to release the ref on the resource.

Right, I completely forgot about the deadlocking

-- 
Best regards,
Dmitry


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 12/23] drm/shmem-helper: Add and use pages_pin_count
  2023-08-28 11:46   ` Boris Brezillon
@ 2023-08-29  2:30     ` Dmitry Osipenko
  0 siblings, 0 replies; 53+ messages in thread
From: Dmitry Osipenko @ 2023-08-29  2:30 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Emma Anholt, Melissa Wen, Will Deacon, Peter Zijlstra,
	Boqun Feng, Mark Rutland, dri-devel, linux-kernel, kernel,
	virtualization, intel-gfx

On 8/28/23 14:46, Boris Brezillon wrote:
> On Sun, 27 Aug 2023 20:54:38 +0300
> Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:
> 
>> Add separate pages_pin_count for tracking of whether drm-shmem pages are
>> moveable or not. With the addition of memory shrinker support to drm-shmem,
>> the pages_use_count will no longer determine whether pages are hard-pinned
>> in memory, but whether pages exit and are soft-pinned (and could be swapped
>> out). The pages_pin_count > 1 will hard-pin pages in memory.
>>
>> Suggested-by: Boris Brezillon <boris.brezillon@collabora.com>
>> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
>> ---
>>  drivers/gpu/drm/drm_gem_shmem_helper.c | 22 +++++++++++++++++-----
>>  include/drm/drm_gem_shmem_helper.h     | 10 ++++++++++
>>  2 files changed, 27 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
>> index d545d3d227d7..1a7e5c332fd8 100644
>> --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
>> +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
>> @@ -234,14 +234,22 @@ static int drm_gem_shmem_pin_locked(struct drm_gem_shmem_object *shmem)
>>  
>>  	dma_resv_assert_held(shmem->base.resv);
>>  
>> +	if (kref_get_unless_zero(&shmem->pages_pin_count))
>> +		return 0;
>> +
>>  	ret = drm_gem_shmem_get_pages_locked(shmem);
>> +	if (!ret)
>> +		kref_init(&shmem->pages_pin_count);
>>  
>>  	return ret;
>>  }
>>  
>> -static void drm_gem_shmem_unpin_locked(struct drm_gem_shmem_object *shmem)
>> +static void drm_gem_shmem_kref_unpin_pages(struct kref *kref)
>>  {
>> -	dma_resv_assert_held(shmem->base.resv);
>> +	struct drm_gem_shmem_object *shmem;
>> +
>> +	shmem = container_of(kref, struct drm_gem_shmem_object,
>> +			     pages_pin_count);
>>  
>>  	drm_gem_shmem_put_pages_locked(shmem);
>>  }
>> @@ -263,6 +271,9 @@ int drm_gem_shmem_pin(struct drm_gem_shmem_object *shmem)
>>  
>>  	drm_WARN_ON(obj->dev, obj->import_attach);
>>  
>> +	if (kref_get_unless_zero(&shmem->pages_pin_count))
>> +		return 0;
>> +
>>  	ret = dma_resv_lock_interruptible(shmem->base.resv, NULL);
>>  	if (ret)
>>  		return ret;
>> @@ -286,9 +297,10 @@ void drm_gem_shmem_unpin(struct drm_gem_shmem_object *shmem)
>>  
>>  	drm_WARN_ON(obj->dev, obj->import_attach);
>>  
>> -	dma_resv_lock(shmem->base.resv, NULL);
>> -	drm_gem_shmem_unpin_locked(shmem);
>> -	dma_resv_unlock(shmem->base.resv);
>> +	if (kref_put_dma_resv(&shmem->pages_pin_count,
>> +			      drm_gem_shmem_kref_unpin_pages,
>> +			      obj->resv, NULL))
>> +		dma_resv_unlock(obj->resv);
>>  }
>>  EXPORT_SYMBOL_GPL(drm_gem_shmem_unpin);
>>  
>> diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h
>> index ec2d8b24e3cf..afb7cd671e2a 100644
>> --- a/include/drm/drm_gem_shmem_helper.h
>> +++ b/include/drm/drm_gem_shmem_helper.h
>> @@ -39,6 +39,16 @@ struct drm_gem_shmem_object {
>>  	 */
>>  	unsigned int pages_use_count;
>>  
>> +	/**
>> +	 * @pages_pin_count:
>> +	 *
>> +	 * Reference count on the pinned pages table.
>> +	 * The pages allowed to be evicted and purged by memory
>> +	 * shrinker only when the count is zero, otherwise pages
>> +	 * are hard-pinned in memory.
>> +	 */
>> +	struct kref pages_pin_count;
> 
> I know it's tempting to use kref for the pages use/pin count, but I'm
> wondering if we wouldn't be better using a refcount_t, which provides
> overflow/underflow protection while still letting us control how we
> want to handle the locking for 0 <-> 1 transitions. By doing that, we
> avoid introducing core locking changes that might be more
> controversial/longer to get accepted. Besides, I suspect the resulting
> code (the one using a refcount_t) won't be more verbose/complicated (no
> release functions needed if you don't use kref_put(), which makes
> things closer to what we have right now).

Alright, let's try to use refcount_t since Christian also doesn't like kref

-- 
Best regards,
Dmitry


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 17/23] drm/shmem-helper: Add and use drm_gem_shmem_resv_assert_held() helper
  2023-08-28 10:12   ` Boris Brezillon
@ 2023-08-29  2:34     ` Dmitry Osipenko
  2023-08-29  7:29       ` Boris Brezillon
  0 siblings, 1 reply; 53+ messages in thread
From: Dmitry Osipenko @ 2023-08-29  2:34 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Emma Anholt, Melissa Wen, Will Deacon, Peter Zijlstra,
	Boqun Feng, Mark Rutland, dri-devel, linux-kernel, kernel,
	virtualization, intel-gfx

On 8/28/23 13:12, Boris Brezillon wrote:
> On Sun, 27 Aug 2023 20:54:43 +0300
> Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:
> 
>> In a preparation of adding drm-shmem memory shrinker, move all reservation
>> locking lockdep checks to use new drm_gem_shmem_resv_assert_held() that
>> will resolve spurious lockdep warning about wrong locking order vs
>> fs_reclam code paths during freeing of shmem GEM, where lockdep isn't
>> aware that it's impossible to have locking contention with the fs_reclam
>> at this special time.
>>
>> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
>> ---
>>  drivers/gpu/drm/drm_gem_shmem_helper.c | 37 +++++++++++++++++---------
>>  1 file changed, 25 insertions(+), 12 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
>> index d96fee3d6166..ca5da976aafa 100644
>> --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
>> +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
>> @@ -128,6 +128,23 @@ struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t
>>  }
>>  EXPORT_SYMBOL_GPL(drm_gem_shmem_create);
>>  
>> +static void drm_gem_shmem_resv_assert_held(struct drm_gem_shmem_object *shmem)
>> +{
>> +	/*
>> +	 * Destroying the object is a special case.. drm_gem_shmem_free()
>> +	 * calls many things that WARN_ON if the obj lock is not held.  But
>> +	 * acquiring the obj lock in drm_gem_shmem_free() can cause a locking
>> +	 * order inversion between reservation_ww_class_mutex and fs_reclaim.
>> +	 *
>> +	 * This deadlock is not actually possible, because no one should
>> +	 * be already holding the lock when drm_gem_shmem_free() is called.
>> +	 * Unfortunately lockdep is not aware of this detail.  So when the
>> +	 * refcount drops to zero, we pretend it is already locked.
>> +	 */
>> +	if (kref_read(&shmem->base.refcount))
>> +		drm_gem_shmem_resv_assert_held(shmem);
>> +}
>> +
>>  /**
>>   * drm_gem_shmem_free - Free resources associated with a shmem GEM object
>>   * @shmem: shmem GEM object to free
>> @@ -142,8 +159,6 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
>>  	if (obj->import_attach) {
>>  		drm_prime_gem_destroy(obj, shmem->sgt);
>>  	} else if (!shmem->imported_sgt) {
>> -		dma_resv_lock(shmem->base.resv, NULL);
>> -
>>  		drm_WARN_ON(obj->dev, kref_read(&shmem->vmap_use_count));
>>  
>>  		if (shmem->sgt) {
>> @@ -156,8 +171,6 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
>>  			drm_gem_shmem_put_pages_locked(shmem);
> 
> AFAICT, drm_gem_shmem_put_pages_locked() is the only function that's
> called in the free path and would complain about resv-lock not being
> held. I think I'd feel more comfortable if we were adding a
> drm_gem_shmem_free_pages() function that did everything
> drm_gem_shmem_put_pages_locked() does except for the lock_held() check
> and the refcount dec, and have it called here (and in
> drm_gem_shmem_put_pages_locked()). This way we can keep using
> dma_resv_assert_held() instead of having our own variant.

It's not only drm_gem_shmem_free_pages(), but any drm-shmem function
that drivers may use in the GEM's freeing callback.

For example, panfrost_gem_free_object() may unpin shmem BO and then do
drm_gem_shmem_free().

-- 
Best regards,
Dmitry


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers
  2023-08-28 15:24   ` Helen Mae Koike Fornazier
@ 2023-08-29  2:36     ` Dmitry Osipenko
  0 siblings, 0 replies; 53+ messages in thread
From: Dmitry Osipenko @ 2023-08-29  2:36 UTC (permalink / raw)
  To: Helen Mae Koike Fornazier
  Cc: Mark Rutland, Emma Anholt, Peter Zijlstra, dri-devel,
	Gurchetan Singh, Gerd Hoffmann, kernel, Will Deacon,
	Steven Price, intel-gfx, Boqun Feng, Maxime Ripard, Melissa Wen,
	virtualization, linux-kernel, Boris Brezillon, Qiang Yu,
	Thomas Zimmermann, Christian König

On 8/28/23 18:24, Helen Mae Koike Fornazier wrote:
> On Monday, August 28, 2023 11:37 -03, "Helen Mae Koike Fornazier" <helen.koike@collabora.com> wrote:
> 
>> On Sunday, August 27, 2023 14:54 -03, Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:
>>
>>> This series:
>>>
>>>   1. Adds common drm-shmem memory shrinker
>>>   2. Enables shrinker for VirtIO-GPU driver
>>>   3. Switches Panfrost driver to the common shrinker
>>
>> Hi Dmitry, 
>>
>> Would you mind testing with drm-ci? We virt-io tests there and it would be
>> really great to get your feedback of it.
>>
>> https://cgit.freedesktop.org/drm/drm/log/?h=topic/drm-ci
> 
> sorry, I forgot that you also need this patchset:
>     https://lists.freedesktop.org/archives/dri-devel/2023-August/420063.html
> to enable virtio_gpu test job.
> 
> Thanks again.
> Helen
> 
>>
>> You need to merge your changes with the above tree.
>> To configure it, you just need to have a tree on gitlab.freedesktop.org,
>> go to the settings and change the CI/CD configuration file from .gitlab-ci.yml
>> to drivers/gpu/drm/ci/gitlab-ci.yml, and you can start a pipeline
>> on your branch.
>>
>> at the time of this writting, gitlab.freedesktop.org is under maintenance,
>> but it should be back soon.

Thanks, Helen. I'll give it a try for the next version

-- 
Best regards,
Dmitry


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 17/23] drm/shmem-helper: Add and use drm_gem_shmem_resv_assert_held() helper
  2023-08-29  2:34     ` Dmitry Osipenko
@ 2023-08-29  7:29       ` Boris Brezillon
  2023-08-29  8:52         ` Christian König
  2023-09-02 19:43         ` Dmitry Osipenko
  0 siblings, 2 replies; 53+ messages in thread
From: Boris Brezillon @ 2023-08-29  7:29 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Emma Anholt, Melissa Wen, Will Deacon, Peter Zijlstra,
	Boqun Feng, Mark Rutland, dri-devel, linux-kernel, kernel,
	virtualization, intel-gfx

On Tue, 29 Aug 2023 05:34:23 +0300
Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:

> On 8/28/23 13:12, Boris Brezillon wrote:
> > On Sun, 27 Aug 2023 20:54:43 +0300
> > Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:
> >   
> >> In a preparation of adding drm-shmem memory shrinker, move all reservation
> >> locking lockdep checks to use new drm_gem_shmem_resv_assert_held() that
> >> will resolve spurious lockdep warning about wrong locking order vs
> >> fs_reclam code paths during freeing of shmem GEM, where lockdep isn't
> >> aware that it's impossible to have locking contention with the fs_reclam
> >> at this special time.
> >>
> >> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
> >> ---
> >>  drivers/gpu/drm/drm_gem_shmem_helper.c | 37 +++++++++++++++++---------
> >>  1 file changed, 25 insertions(+), 12 deletions(-)
> >>
> >> diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
> >> index d96fee3d6166..ca5da976aafa 100644
> >> --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
> >> +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
> >> @@ -128,6 +128,23 @@ struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t
> >>  }
> >>  EXPORT_SYMBOL_GPL(drm_gem_shmem_create);
> >>  
> >> +static void drm_gem_shmem_resv_assert_held(struct drm_gem_shmem_object *shmem)
> >> +{
> >> +	/*
> >> +	 * Destroying the object is a special case.. drm_gem_shmem_free()
> >> +	 * calls many things that WARN_ON if the obj lock is not held.  But
> >> +	 * acquiring the obj lock in drm_gem_shmem_free() can cause a locking
> >> +	 * order inversion between reservation_ww_class_mutex and fs_reclaim.
> >> +	 *
> >> +	 * This deadlock is not actually possible, because no one should
> >> +	 * be already holding the lock when drm_gem_shmem_free() is called.
> >> +	 * Unfortunately lockdep is not aware of this detail.  So when the
> >> +	 * refcount drops to zero, we pretend it is already locked.
> >> +	 */
> >> +	if (kref_read(&shmem->base.refcount))
> >> +		drm_gem_shmem_resv_assert_held(shmem);
> >> +}
> >> +
> >>  /**
> >>   * drm_gem_shmem_free - Free resources associated with a shmem GEM object
> >>   * @shmem: shmem GEM object to free
> >> @@ -142,8 +159,6 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
> >>  	if (obj->import_attach) {
> >>  		drm_prime_gem_destroy(obj, shmem->sgt);
> >>  	} else if (!shmem->imported_sgt) {
> >> -		dma_resv_lock(shmem->base.resv, NULL);
> >> -
> >>  		drm_WARN_ON(obj->dev, kref_read(&shmem->vmap_use_count));
> >>  
> >>  		if (shmem->sgt) {
> >> @@ -156,8 +171,6 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
> >>  			drm_gem_shmem_put_pages_locked(shmem);  
> > 
> > AFAICT, drm_gem_shmem_put_pages_locked() is the only function that's
> > called in the free path and would complain about resv-lock not being
> > held. I think I'd feel more comfortable if we were adding a
> > drm_gem_shmem_free_pages() function that did everything
> > drm_gem_shmem_put_pages_locked() does except for the lock_held() check
> > and the refcount dec, and have it called here (and in
> > drm_gem_shmem_put_pages_locked()). This way we can keep using
> > dma_resv_assert_held() instead of having our own variant.  
> 
> It's not only drm_gem_shmem_free_pages(), but any drm-shmem function
> that drivers may use in the GEM's freeing callback.
> 
> For example, panfrost_gem_free_object() may unpin shmem BO and then do
> drm_gem_shmem_free().

Is this really a valid use case? If the GEM refcount dropped to zero,
we should certainly not have pages_pin_count > 0 (thinking of vmap-ed
buffers that might disappear while kernel still has a pointer to the
CPU-mapped area). The only reason we have this
drm_gem_shmem_put_pages_locked() in drm_gem_shmem_free() is because of
this implicit ref hold by the sgt, and IMHO, we should be stricter and
check that pages_use_count == 1 when sgt != NULL and pages_use_count ==
0 otherwise.

I actually think it's a good thing to try and catch any attempt to call
functions trying lock the resv in a path they're not supposed to. At
least we can decide whether these actions are valid or not in this
context, and provide dedicated helpers for the free path if they are.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 17/23] drm/shmem-helper: Add and use drm_gem_shmem_resv_assert_held() helper
  2023-08-29  7:29       ` Boris Brezillon
@ 2023-08-29  8:52         ` Christian König
  2023-08-29  9:44           ` Boris Brezillon
  2023-09-02 19:43         ` Dmitry Osipenko
  1 sibling, 1 reply; 53+ messages in thread
From: Christian König @ 2023-08-29  8:52 UTC (permalink / raw)
  To: Boris Brezillon, Dmitry Osipenko
  Cc: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Qiang Yu, Steven Price, Emma Anholt,
	Melissa Wen, Will Deacon, Peter Zijlstra, Boqun Feng,
	Mark Rutland, dri-devel, linux-kernel, kernel, virtualization,
	intel-gfx

Am 29.08.23 um 09:29 schrieb Boris Brezillon:
> On Tue, 29 Aug 2023 05:34:23 +0300
> Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:
>
>> On 8/28/23 13:12, Boris Brezillon wrote:
>>> On Sun, 27 Aug 2023 20:54:43 +0300
>>> Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:
>>>    
>>>> In a preparation of adding drm-shmem memory shrinker, move all reservation
>>>> locking lockdep checks to use new drm_gem_shmem_resv_assert_held() that
>>>> will resolve spurious lockdep warning about wrong locking order vs
>>>> fs_reclam code paths during freeing of shmem GEM, where lockdep isn't
>>>> aware that it's impossible to have locking contention with the fs_reclam
>>>> at this special time.
>>>>
>>>> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
>>>> ---
>>>>   drivers/gpu/drm/drm_gem_shmem_helper.c | 37 +++++++++++++++++---------
>>>>   1 file changed, 25 insertions(+), 12 deletions(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
>>>> index d96fee3d6166..ca5da976aafa 100644
>>>> --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
>>>> +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
>>>> @@ -128,6 +128,23 @@ struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t
>>>>   }
>>>>   EXPORT_SYMBOL_GPL(drm_gem_shmem_create);
>>>>   
>>>> +static void drm_gem_shmem_resv_assert_held(struct drm_gem_shmem_object *shmem)
>>>> +{
>>>> +	/*
>>>> +	 * Destroying the object is a special case.. drm_gem_shmem_free()
>>>> +	 * calls many things that WARN_ON if the obj lock is not held.  But
>>>> +	 * acquiring the obj lock in drm_gem_shmem_free() can cause a locking
>>>> +	 * order inversion between reservation_ww_class_mutex and fs_reclaim.
>>>> +	 *
>>>> +	 * This deadlock is not actually possible, because no one should
>>>> +	 * be already holding the lock when drm_gem_shmem_free() is called.
>>>> +	 * Unfortunately lockdep is not aware of this detail.  So when the
>>>> +	 * refcount drops to zero, we pretend it is already locked.
>>>> +	 */
>>>> +	if (kref_read(&shmem->base.refcount))
>>>> +		drm_gem_shmem_resv_assert_held(shmem);
>>>> +}
>>>> +
>>>>   /**
>>>>    * drm_gem_shmem_free - Free resources associated with a shmem GEM object
>>>>    * @shmem: shmem GEM object to free
>>>> @@ -142,8 +159,6 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
>>>>   	if (obj->import_attach) {
>>>>   		drm_prime_gem_destroy(obj, shmem->sgt);
>>>>   	} else if (!shmem->imported_sgt) {
>>>> -		dma_resv_lock(shmem->base.resv, NULL);
>>>> -
>>>>   		drm_WARN_ON(obj->dev, kref_read(&shmem->vmap_use_count));
>>>>   
>>>>   		if (shmem->sgt) {
>>>> @@ -156,8 +171,6 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
>>>>   			drm_gem_shmem_put_pages_locked(shmem);
>>> AFAICT, drm_gem_shmem_put_pages_locked() is the only function that's
>>> called in the free path and would complain about resv-lock not being
>>> held. I think I'd feel more comfortable if we were adding a
>>> drm_gem_shmem_free_pages() function that did everything
>>> drm_gem_shmem_put_pages_locked() does except for the lock_held() check
>>> and the refcount dec, and have it called here (and in
>>> drm_gem_shmem_put_pages_locked()). This way we can keep using
>>> dma_resv_assert_held() instead of having our own variant.
>> It's not only drm_gem_shmem_free_pages(), but any drm-shmem function
>> that drivers may use in the GEM's freeing callback.
>>
>> For example, panfrost_gem_free_object() may unpin shmem BO and then do
>> drm_gem_shmem_free().
> Is this really a valid use case?

I haven't followed the whole discussion, but I think it isn't a valid 
use case.

That page_use_count is none zero while the GEM object is about to be 
destroyed can only happen is someone managed to grab a reference to the 
page without referencing the GEM object.

This is turn usually happens when somebody incorrectly walks the CPU 
page tables and grabs page references where it shouldn't. KMS used to do 
this and we had already had a discussion that they shouldn't do this.

Regards,
Christian.


>   If the GEM refcount dropped to zero,
> we should certainly not have pages_pin_count > 0 (thinking of vmap-ed
> buffers that might disappear while kernel still has a pointer to the
> CPU-mapped area). The only reason we have this
> drm_gem_shmem_put_pages_locked() in drm_gem_shmem_free() is because of
> this implicit ref hold by the sgt, and IMHO, we should be stricter and
> check that pages_use_count == 1 when sgt != NULL and pages_use_count ==
> 0 otherwise.
>
> I actually think it's a good thing to try and catch any attempt to call
> functions trying lock the resv in a path they're not supposed to. At
> least we can decide whether these actions are valid or not in this
> context, and provide dedicated helpers for the free path if they are.


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 17/23] drm/shmem-helper: Add and use drm_gem_shmem_resv_assert_held() helper
  2023-08-29  8:52         ` Christian König
@ 2023-08-29  9:44           ` Boris Brezillon
  2023-08-29 10:21             ` Boris Brezillon
  0 siblings, 1 reply; 53+ messages in thread
From: Boris Brezillon @ 2023-08-29  9:44 UTC (permalink / raw)
  To: Christian König
  Cc: Dmitry Osipenko, David Airlie, Gerd Hoffmann, Gurchetan Singh,
	Chia-I Wu, Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Qiang Yu, Steven Price, Emma Anholt,
	Melissa Wen, Will Deacon, Peter Zijlstra, Boqun Feng,
	Mark Rutland, dri-devel, linux-kernel, kernel, virtualization,
	intel-gfx

On Tue, 29 Aug 2023 10:52:03 +0200
Christian König <christian.koenig@amd.com> wrote:

> Am 29.08.23 um 09:29 schrieb Boris Brezillon:
> > On Tue, 29 Aug 2023 05:34:23 +0300
> > Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:
> >  
> >> On 8/28/23 13:12, Boris Brezillon wrote:  
> >>> On Sun, 27 Aug 2023 20:54:43 +0300
> >>> Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:
> >>>      
> >>>> In a preparation of adding drm-shmem memory shrinker, move all reservation
> >>>> locking lockdep checks to use new drm_gem_shmem_resv_assert_held() that
> >>>> will resolve spurious lockdep warning about wrong locking order vs
> >>>> fs_reclam code paths during freeing of shmem GEM, where lockdep isn't
> >>>> aware that it's impossible to have locking contention with the fs_reclam
> >>>> at this special time.
> >>>>
> >>>> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
> >>>> ---
> >>>>   drivers/gpu/drm/drm_gem_shmem_helper.c | 37 +++++++++++++++++---------
> >>>>   1 file changed, 25 insertions(+), 12 deletions(-)
> >>>>
> >>>> diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
> >>>> index d96fee3d6166..ca5da976aafa 100644
> >>>> --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
> >>>> +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
> >>>> @@ -128,6 +128,23 @@ struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t
> >>>>   }
> >>>>   EXPORT_SYMBOL_GPL(drm_gem_shmem_create);
> >>>>   
> >>>> +static void drm_gem_shmem_resv_assert_held(struct drm_gem_shmem_object *shmem)
> >>>> +{
> >>>> +	/*
> >>>> +	 * Destroying the object is a special case.. drm_gem_shmem_free()
> >>>> +	 * calls many things that WARN_ON if the obj lock is not held.  But
> >>>> +	 * acquiring the obj lock in drm_gem_shmem_free() can cause a locking
> >>>> +	 * order inversion between reservation_ww_class_mutex and fs_reclaim.
> >>>> +	 *
> >>>> +	 * This deadlock is not actually possible, because no one should
> >>>> +	 * be already holding the lock when drm_gem_shmem_free() is called.
> >>>> +	 * Unfortunately lockdep is not aware of this detail.  So when the
> >>>> +	 * refcount drops to zero, we pretend it is already locked.
> >>>> +	 */
> >>>> +	if (kref_read(&shmem->base.refcount))
> >>>> +		drm_gem_shmem_resv_assert_held(shmem);
> >>>> +}
> >>>> +
> >>>>   /**
> >>>>    * drm_gem_shmem_free - Free resources associated with a shmem GEM object
> >>>>    * @shmem: shmem GEM object to free
> >>>> @@ -142,8 +159,6 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
> >>>>   	if (obj->import_attach) {
> >>>>   		drm_prime_gem_destroy(obj, shmem->sgt);
> >>>>   	} else if (!shmem->imported_sgt) {
> >>>> -		dma_resv_lock(shmem->base.resv, NULL);
> >>>> -
> >>>>   		drm_WARN_ON(obj->dev, kref_read(&shmem->vmap_use_count));
> >>>>   
> >>>>   		if (shmem->sgt) {
> >>>> @@ -156,8 +171,6 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
> >>>>   			drm_gem_shmem_put_pages_locked(shmem);  
> >>> AFAICT, drm_gem_shmem_put_pages_locked() is the only function that's
> >>> called in the free path and would complain about resv-lock not being
> >>> held. I think I'd feel more comfortable if we were adding a
> >>> drm_gem_shmem_free_pages() function that did everything
> >>> drm_gem_shmem_put_pages_locked() does except for the lock_held() check
> >>> and the refcount dec, and have it called here (and in
> >>> drm_gem_shmem_put_pages_locked()). This way we can keep using
> >>> dma_resv_assert_held() instead of having our own variant.  
> >> It's not only drm_gem_shmem_free_pages(), but any drm-shmem function
> >> that drivers may use in the GEM's freeing callback.
> >>
> >> For example, panfrost_gem_free_object() may unpin shmem BO and then do
> >> drm_gem_shmem_free().  
> > Is this really a valid use case?  
> 
> I haven't followed the whole discussion, but I think it isn't a valid 
> use case.
> 
> That page_use_count is none zero while the GEM object is about to be 
> destroyed can only happen is someone managed to grab a reference to the 
> page without referencing the GEM object.

Actually, drm_gem_shmem_object is a bit special (weird?) in this regard.
drm_gem_shmem_get_pages_sgt_locked() creates the sgt and takes a
pages ref (pages_use_count++). The sgt itself is cached (next call to
drm_gem_shmem_get_pages_sgt_locked() will return the existing sgt) but
not refcounted, which means it will stay around until the GEM object is
destroyed or its pages are purged (GEM eviction). Because of that,
shmem->pages_use_count == 1 in drm_gem_shmem_free_pages() is valid iff
shmem->sgt != NULL. pages_use_count > 1 is invalid though, as should be
pages_pin_count after Dmitry's patches.

If we want to 'fix' that (not convinced this is a bug, more a design
choice), we need to refcount the sgt users and add
drm_gem_shmem_put_pages_sgt[_locked](), so drivers can reflect when
they're done using the sgt.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 17/23] drm/shmem-helper: Add and use drm_gem_shmem_resv_assert_held() helper
  2023-08-29  9:44           ` Boris Brezillon
@ 2023-08-29 10:21             ` Boris Brezillon
  0 siblings, 0 replies; 53+ messages in thread
From: Boris Brezillon @ 2023-08-29 10:21 UTC (permalink / raw)
  To: Christian König
  Cc: Dmitry Osipenko, David Airlie, Gerd Hoffmann, Gurchetan Singh,
	Chia-I Wu, Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Qiang Yu, Steven Price, Emma Anholt,
	Melissa Wen, Will Deacon, Peter Zijlstra, Boqun Feng,
	Mark Rutland, dri-devel, linux-kernel, kernel, virtualization,
	intel-gfx

On Tue, 29 Aug 2023 11:44:13 +0200
Boris Brezillon <boris.brezillon@collabora.com> wrote:

> On Tue, 29 Aug 2023 10:52:03 +0200
> Christian König <christian.koenig@amd.com> wrote:
> 
> > Am 29.08.23 um 09:29 schrieb Boris Brezillon:  
> > > On Tue, 29 Aug 2023 05:34:23 +0300
> > > Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:
> > >    
> > >> On 8/28/23 13:12, Boris Brezillon wrote:    
> > >>> On Sun, 27 Aug 2023 20:54:43 +0300
> > >>> Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:
> > >>>        
> > >>>> In a preparation of adding drm-shmem memory shrinker, move all reservation
> > >>>> locking lockdep checks to use new drm_gem_shmem_resv_assert_held() that
> > >>>> will resolve spurious lockdep warning about wrong locking order vs
> > >>>> fs_reclam code paths during freeing of shmem GEM, where lockdep isn't
> > >>>> aware that it's impossible to have locking contention with the fs_reclam
> > >>>> at this special time.
> > >>>>
> > >>>> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
> > >>>> ---
> > >>>>   drivers/gpu/drm/drm_gem_shmem_helper.c | 37 +++++++++++++++++---------
> > >>>>   1 file changed, 25 insertions(+), 12 deletions(-)
> > >>>>
> > >>>> diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
> > >>>> index d96fee3d6166..ca5da976aafa 100644
> > >>>> --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
> > >>>> +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
> > >>>> @@ -128,6 +128,23 @@ struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t
> > >>>>   }
> > >>>>   EXPORT_SYMBOL_GPL(drm_gem_shmem_create);
> > >>>>   
> > >>>> +static void drm_gem_shmem_resv_assert_held(struct drm_gem_shmem_object *shmem)
> > >>>> +{
> > >>>> +	/*
> > >>>> +	 * Destroying the object is a special case.. drm_gem_shmem_free()
> > >>>> +	 * calls many things that WARN_ON if the obj lock is not held.  But
> > >>>> +	 * acquiring the obj lock in drm_gem_shmem_free() can cause a locking
> > >>>> +	 * order inversion between reservation_ww_class_mutex and fs_reclaim.
> > >>>> +	 *
> > >>>> +	 * This deadlock is not actually possible, because no one should
> > >>>> +	 * be already holding the lock when drm_gem_shmem_free() is called.
> > >>>> +	 * Unfortunately lockdep is not aware of this detail.  So when the
> > >>>> +	 * refcount drops to zero, we pretend it is already locked.
> > >>>> +	 */
> > >>>> +	if (kref_read(&shmem->base.refcount))
> > >>>> +		drm_gem_shmem_resv_assert_held(shmem);
> > >>>> +}
> > >>>> +
> > >>>>   /**
> > >>>>    * drm_gem_shmem_free - Free resources associated with a shmem GEM object
> > >>>>    * @shmem: shmem GEM object to free
> > >>>> @@ -142,8 +159,6 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
> > >>>>   	if (obj->import_attach) {
> > >>>>   		drm_prime_gem_destroy(obj, shmem->sgt);
> > >>>>   	} else if (!shmem->imported_sgt) {
> > >>>> -		dma_resv_lock(shmem->base.resv, NULL);
> > >>>> -
> > >>>>   		drm_WARN_ON(obj->dev, kref_read(&shmem->vmap_use_count));
> > >>>>   
> > >>>>   		if (shmem->sgt) {
> > >>>> @@ -156,8 +171,6 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
> > >>>>   			drm_gem_shmem_put_pages_locked(shmem);    
> > >>> AFAICT, drm_gem_shmem_put_pages_locked() is the only function that's
> > >>> called in the free path and would complain about resv-lock not being
> > >>> held. I think I'd feel more comfortable if we were adding a
> > >>> drm_gem_shmem_free_pages() function that did everything
> > >>> drm_gem_shmem_put_pages_locked() does except for the lock_held() check
> > >>> and the refcount dec, and have it called here (and in
> > >>> drm_gem_shmem_put_pages_locked()). This way we can keep using
> > >>> dma_resv_assert_held() instead of having our own variant.    
> > >> It's not only drm_gem_shmem_free_pages(), but any drm-shmem function
> > >> that drivers may use in the GEM's freeing callback.
> > >>
> > >> For example, panfrost_gem_free_object() may unpin shmem BO and then do
> > >> drm_gem_shmem_free().    
> > > Is this really a valid use case?    
> > 
> > I haven't followed the whole discussion, but I think it isn't a valid 
> > use case.
> > 
> > That page_use_count is none zero while the GEM object is about to be 
> > destroyed can only happen is someone managed to grab a reference to the 
> > page without referencing the GEM object.  
> 
> Actually, drm_gem_shmem_object is a bit special (weird?) in this regard.
> drm_gem_shmem_get_pages_sgt_locked() creates the sgt and takes a
> pages ref (pages_use_count++). The sgt itself is cached (next call to
> drm_gem_shmem_get_pages_sgt_locked() will return the existing sgt) but
> not refcounted, which means it will stay around until the GEM object is
> destroyed or its pages are purged (GEM eviction). Because of that,
> shmem->pages_use_count == 1 in drm_gem_shmem_free_pages() is valid iff
> shmem->sgt != NULL. pages_use_count > 1 is invalid though, as should be
> pages_pin_count after Dmitry's patches.
> 
> If we want to 'fix' that (not convinced this is a bug, more a design
> choice), we need to refcount the sgt users and add
> drm_gem_shmem_put_pages_sgt[_locked](), so drivers can reflect when
> they're done using the sgt.

Or we simply create the sgt in drm_gem_shmem_get_pages_locked(), and
make drm_gem_shmem_get_pages_sgt() a dummy wrapper returning
shmem->sgt, which will force callers to explicitly call
drm_gem_shmem_{get,pin}_pages[_locked]() if they want a non-NULL sgt.
By doing that, we avoid adding yet another level of refcounting and we
keep drivers responsible for pages_{use,pin}_count balancing. The only
downside would be the unconditional creation of the sg_table, but I
suspect all current users of drm_gem_shmem_object want this sg_table
anyway.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 01/23] drm/shmem-helper: Fix UAF in error path when freeing SGT of imported GEM
  2023-08-28 11:16   ` Boris Brezillon
@ 2023-09-02 18:15     ` Dmitry Osipenko
  2023-09-04  8:01       ` Boris Brezillon
  0 siblings, 1 reply; 53+ messages in thread
From: Dmitry Osipenko @ 2023-09-02 18:15 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Emma Anholt, Melissa Wen, Will Deacon, Peter Zijlstra,
	Boqun Feng, Mark Rutland, dri-devel, linux-kernel, kernel,
	virtualization, intel-gfx

On 8/28/23 14:16, Boris Brezillon wrote:
> On Sun, 27 Aug 2023 20:54:27 +0300
> Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:
> 
>> Freeing drm-shmem GEM right after creating it using
>> drm_gem_shmem_prime_import_sg_table() frees SGT of the imported dma-buf
>> and then dma-buf frees this SGT second time.
>>
>> The v3d_prime_import_sg_table() is example of a error code path where
>> dma-buf's SGT is freed by drm-shmem and then it's freed second time by
>> dma_buf_unmap_attachment() in drm_gem_prime_import_dev().
>>
>> Add drm-shmem GEM flag telling that this is imported SGT shall not be
>> treated as own SGT, fixing the use-after-free bug.
>>
>> Cc: stable@vger.kernel.org
>> Fixes: 2194a63a818d ("drm: Add library for shmem backed GEM objects")
>> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
>> ---
>>  drivers/gpu/drm/drm_gem_shmem_helper.c | 3 ++-
>>  include/drm/drm_gem_shmem_helper.h     | 7 +++++++
>>  2 files changed, 9 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
>> index a783d2245599..78d9cf2355a5 100644
>> --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
>> +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
>> @@ -141,7 +141,7 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
>>  
>>  	if (obj->import_attach) {
>>  		drm_prime_gem_destroy(obj, shmem->sgt);
>> -	} else {
>> +	} else if (!shmem->imported_sgt) {
>>  		dma_resv_lock(shmem->base.resv, NULL);
>>  
>>  		drm_WARN_ON(obj->dev, shmem->vmap_use_count);
>> @@ -758,6 +758,7 @@ drm_gem_shmem_prime_import_sg_table(struct drm_device *dev,
>>  		return ERR_CAST(shmem);
>>  
>>  	shmem->sgt = sgt;
>> +	shmem->imported_sgt = true;
> 
> 
> I feel like adding more fields that can be used to do the is_imported()
> check is going to be even more confusing. Can we instead have
> 
> 	/* drm_gem_shmem_prime_import_sg_table() can be called from a
> 	 * driver specific ->import_sg_table() implementations that
> 	 * have extra failable initialization steps. Assign
> 	 * drm_gem_object::import_attach here (even though it's
> 	 * assigned in drm_gem_prime_import_dev()), so we don't end up
> 	 * with driver error paths calling drm_gem_shmem_free() with an
> 	 * imported sg_table assigned to drm_gem_shmem_object::sgt and
> 	 * drm_gem_object::import_attach left uninitialized.
> 	 */
> 	shmem->base.import_attach = attach;
> 
> here?

AFAICT, this is not going to work because obj->import_attach will be
released by drm_prime core by the time drm_gem_shmem_free() is invoked
and drm_gem_shmem_free() uses obj->import_attach as well. I'll keep this
patch around unless there will be other suggestions. To me the flag is
good enough, I'll add a clarifying comment to the code in v16.

-- 
Best regards,
Dmitry


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 02/23] drm/shmem-helper: Use flag for tracking page count bumped by get_pages_sgt()
  2023-08-28 10:55   ` Boris Brezillon
@ 2023-09-02 18:28     ` Dmitry Osipenko
  2023-09-04  7:52       ` Boris Brezillon
  0 siblings, 1 reply; 53+ messages in thread
From: Dmitry Osipenko @ 2023-09-02 18:28 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Emma Anholt, Melissa Wen, Will Deacon, Peter Zijlstra,
	Boqun Feng, Mark Rutland, dri-devel, linux-kernel, kernel,
	virtualization, intel-gfx

On 8/28/23 13:55, Boris Brezillon wrote:
> On Sun, 27 Aug 2023 20:54:28 +0300
> Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:
> 
>> Use separate flag for tracking page count bumped by shmem->sgt to avoid
>> imbalanced page counter during of drm_gem_shmem_free() time. It's fragile
>> to assume that populated shmem->pages at a freeing time means that the
>> count was bumped by drm_gem_shmem_get_pages_sgt(), using a flag removes
>> the ambiguity.
>>
>> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
>> ---
>>  drivers/gpu/drm/drm_gem_shmem_helper.c | 3 ++-
>>  drivers/gpu/drm/lima/lima_gem.c        | 1 +
>>  include/drm/drm_gem_shmem_helper.h     | 7 +++++++
>>  3 files changed, 10 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
>> index 78d9cf2355a5..db20b9123891 100644
>> --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
>> +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
>> @@ -152,7 +152,7 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
>>  			sg_free_table(shmem->sgt);
>>  			kfree(shmem->sgt);
>>  		}
>> -		if (shmem->pages)
>> +		if (shmem->got_sgt)
>>  			drm_gem_shmem_put_pages(shmem);
> 
> Can't we just move this drm_gem_shmem_put_pages() call in the
> if (shmem->sgt) block?

As you've seen in patch #1, the shmem->sgt may belong to imported dmabuf
and pages aren't referenced in this case.

I agree that the freeing code is confusing. The flags make it a better,
not ideal. Though, the flags+comments solution is good enough to me.
Please let me know if you have more suggestions, otherwise I'll add
comment to the code and keep this patch for v16.

BTW, I realized that the new flag wasn't placed properly in the Lima
driver, causing unbalanced page count in the error path. Will correct it
in v16.

-- 
Best regards,
Dmitry


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 17/23] drm/shmem-helper: Add and use drm_gem_shmem_resv_assert_held() helper
  2023-08-29  7:29       ` Boris Brezillon
  2023-08-29  8:52         ` Christian König
@ 2023-09-02 19:43         ` Dmitry Osipenko
  2023-09-04  8:36           ` Boris Brezillon
  1 sibling, 1 reply; 53+ messages in thread
From: Dmitry Osipenko @ 2023-09-02 19:43 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Emma Anholt, Melissa Wen, Will Deacon, Peter Zijlstra,
	Boqun Feng, Mark Rutland, dri-devel, linux-kernel, kernel,
	virtualization, intel-gfx

On 8/29/23 10:29, Boris Brezillon wrote:
> On Tue, 29 Aug 2023 05:34:23 +0300
> Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:
> 
>> On 8/28/23 13:12, Boris Brezillon wrote:
>>> On Sun, 27 Aug 2023 20:54:43 +0300
>>> Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:
>>>   
>>>> In a preparation of adding drm-shmem memory shrinker, move all reservation
>>>> locking lockdep checks to use new drm_gem_shmem_resv_assert_held() that
>>>> will resolve spurious lockdep warning about wrong locking order vs
>>>> fs_reclam code paths during freeing of shmem GEM, where lockdep isn't
>>>> aware that it's impossible to have locking contention with the fs_reclam
>>>> at this special time.
>>>>
>>>> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
>>>> ---
>>>>  drivers/gpu/drm/drm_gem_shmem_helper.c | 37 +++++++++++++++++---------
>>>>  1 file changed, 25 insertions(+), 12 deletions(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
>>>> index d96fee3d6166..ca5da976aafa 100644
>>>> --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
>>>> +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
>>>> @@ -128,6 +128,23 @@ struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t
>>>>  }
>>>>  EXPORT_SYMBOL_GPL(drm_gem_shmem_create);
>>>>  
>>>> +static void drm_gem_shmem_resv_assert_held(struct drm_gem_shmem_object *shmem)
>>>> +{
>>>> +	/*
>>>> +	 * Destroying the object is a special case.. drm_gem_shmem_free()
>>>> +	 * calls many things that WARN_ON if the obj lock is not held.  But
>>>> +	 * acquiring the obj lock in drm_gem_shmem_free() can cause a locking
>>>> +	 * order inversion between reservation_ww_class_mutex and fs_reclaim.
>>>> +	 *
>>>> +	 * This deadlock is not actually possible, because no one should
>>>> +	 * be already holding the lock when drm_gem_shmem_free() is called.
>>>> +	 * Unfortunately lockdep is not aware of this detail.  So when the
>>>> +	 * refcount drops to zero, we pretend it is already locked.
>>>> +	 */
>>>> +	if (kref_read(&shmem->base.refcount))
>>>> +		drm_gem_shmem_resv_assert_held(shmem);
>>>> +}
>>>> +
>>>>  /**
>>>>   * drm_gem_shmem_free - Free resources associated with a shmem GEM object
>>>>   * @shmem: shmem GEM object to free
>>>> @@ -142,8 +159,6 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
>>>>  	if (obj->import_attach) {
>>>>  		drm_prime_gem_destroy(obj, shmem->sgt);
>>>>  	} else if (!shmem->imported_sgt) {
>>>> -		dma_resv_lock(shmem->base.resv, NULL);
>>>> -
>>>>  		drm_WARN_ON(obj->dev, kref_read(&shmem->vmap_use_count));
>>>>  
>>>>  		if (shmem->sgt) {
>>>> @@ -156,8 +171,6 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
>>>>  			drm_gem_shmem_put_pages_locked(shmem);  
>>>
>>> AFAICT, drm_gem_shmem_put_pages_locked() is the only function that's
>>> called in the free path and would complain about resv-lock not being
>>> held. I think I'd feel more comfortable if we were adding a
>>> drm_gem_shmem_free_pages() function that did everything
>>> drm_gem_shmem_put_pages_locked() does except for the lock_held() check
>>> and the refcount dec, and have it called here (and in
>>> drm_gem_shmem_put_pages_locked()). This way we can keep using
>>> dma_resv_assert_held() instead of having our own variant.  
>>
>> It's not only drm_gem_shmem_free_pages(), but any drm-shmem function
>> that drivers may use in the GEM's freeing callback.
>>
>> For example, panfrost_gem_free_object() may unpin shmem BO and then do
>> drm_gem_shmem_free().
> 
> Is this really a valid use case? If the GEM refcount dropped to zero,
> we should certainly not have pages_pin_count > 0 (thinking of vmap-ed
> buffers that might disappear while kernel still has a pointer to the
> CPU-mapped area). The only reason we have this
> drm_gem_shmem_put_pages_locked() in drm_gem_shmem_free() is because of
> this implicit ref hold by the sgt, and IMHO, we should be stricter and
> check that pages_use_count == 1 when sgt != NULL and pages_use_count ==
> 0 otherwise.
> 
> I actually think it's a good thing to try and catch any attempt to call
> functions trying lock the resv in a path they're not supposed to. At
> least we can decide whether these actions are valid or not in this
> context, and provide dedicated helpers for the free path if they are.

To me it's a valid use-case. I was going to do it for the virtio-gpu
driver for a specific BO type that should be permanently pinned in
memory. So I made the BO pinned in the virto_gpu's bo_create() and
unpinned it from the virtio-gpu's gem->free(), this is a perfectly valid
case to me. Though, in the end I switched to another approach that
doesn't require to do the pinning in the virtio-gpu driver.

For now we can do it as you suggested, to use custom put_pages() in the
shmem_free() since neither of drivers need that. Let's try that.

-- 
Best regards,
Dmitry


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 16/23] drm/shmem-helper: Use kref for vmap_use_count
  2023-08-28 10:00   ` Boris Brezillon
@ 2023-09-02 20:22     ` Dmitry Osipenko
  0 siblings, 0 replies; 53+ messages in thread
From: Dmitry Osipenko @ 2023-09-02 20:22 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Emma Anholt, Melissa Wen, Will Deacon, Peter Zijlstra,
	Boqun Feng, Mark Rutland, dri-devel, linux-kernel, kernel,
	virtualization, intel-gfx

On 8/28/23 13:00, Boris Brezillon wrote:
> On Sun, 27 Aug 2023 20:54:42 +0300
> Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:
> 
>> Use kref helper for vmap_use_count to make refcounting consistent with
>> pages_use_count and pages_pin_count that use kref. This will allow to
>> optimize unlocked vmappings by skipping reservation locking if refcnt > 1.
> 
> The core is taking the resv lock before calling ->v[un]map(), so
> switching to a kref sounds a bit premature/useless, unless there are
> plans to delegate the locking to the drivers. The only thing it brings
> is standard overflow/underflow checks. Not really sure it's worth
> transitioning to a kref for this field until we have a real use case.

The overflow checks worth transitioning. I'll mention them in the commit
message for v16.

-- 
Best regards,
Dmitry


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 02/23] drm/shmem-helper: Use flag for tracking page count bumped by get_pages_sgt()
  2023-09-02 18:28     ` Dmitry Osipenko
@ 2023-09-04  7:52       ` Boris Brezillon
  0 siblings, 0 replies; 53+ messages in thread
From: Boris Brezillon @ 2023-09-04  7:52 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Emma Anholt, Melissa Wen, Will Deacon, Peter Zijlstra,
	Boqun Feng, Mark Rutland, dri-devel, linux-kernel, kernel,
	virtualization, intel-gfx

On Sat, 2 Sep 2023 21:28:21 +0300
Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:

> On 8/28/23 13:55, Boris Brezillon wrote:
> > On Sun, 27 Aug 2023 20:54:28 +0300
> > Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:
> >   
> >> Use separate flag for tracking page count bumped by shmem->sgt to avoid
> >> imbalanced page counter during of drm_gem_shmem_free() time. It's fragile
> >> to assume that populated shmem->pages at a freeing time means that the
> >> count was bumped by drm_gem_shmem_get_pages_sgt(), using a flag removes
> >> the ambiguity.
> >>
> >> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
> >> ---
> >>  drivers/gpu/drm/drm_gem_shmem_helper.c | 3 ++-
> >>  drivers/gpu/drm/lima/lima_gem.c        | 1 +
> >>  include/drm/drm_gem_shmem_helper.h     | 7 +++++++
> >>  3 files changed, 10 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
> >> index 78d9cf2355a5..db20b9123891 100644
> >> --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
> >> +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
> >> @@ -152,7 +152,7 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
> >>  			sg_free_table(shmem->sgt);
> >>  			kfree(shmem->sgt);
> >>  		}
> >> -		if (shmem->pages)
> >> +		if (shmem->got_sgt)
> >>  			drm_gem_shmem_put_pages(shmem);  
> > 
> > Can't we just move this drm_gem_shmem_put_pages() call in the
> > if (shmem->sgt) block?  
> 
> As you've seen in patch #1, the shmem->sgt may belong to imported dmabuf
> and pages aren't referenced in this case.

Unless I'm wrong, you're already in the if (!import_attach) branch
here, so shmem->sgt should not be a dmabuf sgt.

> 
> I agree that the freeing code is confusing. The flags make it a better,
> not ideal. Though, the flags+comments solution is good enough to me.

But what's the point of adding a flag when you can just do an
if (!shmem->import_attach && shmem->sgt) check. At best, it just
confuses people as to what these fields mean/are used for (especially
when the field has such a generic name, when what you want is actually
something like ->got_sgt_for_non_imported_object). But the most
problematic aspect is that it adds fields to maintain, and those might
end up being inconsistent with the object state because
new/driver-specific code forgot to update them.

> Please let me know if you have more suggestions, otherwise I'll add
> comment to the code and keep this patch for v16.

I'd definitely prefer adding the following helper

static bool has_implicit_pages_ref(struct drm_gem_shmem_object *shmem)
{
	return !shmem->import_attach && shmem->sgt;
}

which provides the same logic without adding a new field/flag.

> 
> BTW, I realized that the new flag wasn't placed properly in the Lima
> driver, causing unbalanced page count in the error path. Will correct it
> in v16.

See, that's the sort of subtle bugs I'm talking about. If the state is
inferred from other fields that can't happen.

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 01/23] drm/shmem-helper: Fix UAF in error path when freeing SGT of imported GEM
  2023-09-02 18:15     ` Dmitry Osipenko
@ 2023-09-04  8:01       ` Boris Brezillon
  0 siblings, 0 replies; 53+ messages in thread
From: Boris Brezillon @ 2023-09-04  8:01 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Emma Anholt, Melissa Wen, Will Deacon, Peter Zijlstra,
	Boqun Feng, Mark Rutland, dri-devel, linux-kernel, kernel,
	virtualization, intel-gfx

On Sat, 2 Sep 2023 21:15:39 +0300
Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:

> On 8/28/23 14:16, Boris Brezillon wrote:
> > On Sun, 27 Aug 2023 20:54:27 +0300
> > Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:
> >   
> >> Freeing drm-shmem GEM right after creating it using
> >> drm_gem_shmem_prime_import_sg_table() frees SGT of the imported dma-buf
> >> and then dma-buf frees this SGT second time.
> >>
> >> The v3d_prime_import_sg_table() is example of a error code path where
> >> dma-buf's SGT is freed by drm-shmem and then it's freed second time by
> >> dma_buf_unmap_attachment() in drm_gem_prime_import_dev().
> >>
> >> Add drm-shmem GEM flag telling that this is imported SGT shall not be
> >> treated as own SGT, fixing the use-after-free bug.
> >>
> >> Cc: stable@vger.kernel.org
> >> Fixes: 2194a63a818d ("drm: Add library for shmem backed GEM objects")
> >> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
> >> ---
> >>  drivers/gpu/drm/drm_gem_shmem_helper.c | 3 ++-
> >>  include/drm/drm_gem_shmem_helper.h     | 7 +++++++
> >>  2 files changed, 9 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
> >> index a783d2245599..78d9cf2355a5 100644
> >> --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
> >> +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
> >> @@ -141,7 +141,7 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
> >>  
> >>  	if (obj->import_attach) {
> >>  		drm_prime_gem_destroy(obj, shmem->sgt);
> >> -	} else {
> >> +	} else if (!shmem->imported_sgt) {
> >>  		dma_resv_lock(shmem->base.resv, NULL);
> >>  
> >>  		drm_WARN_ON(obj->dev, shmem->vmap_use_count);
> >> @@ -758,6 +758,7 @@ drm_gem_shmem_prime_import_sg_table(struct drm_device *dev,
> >>  		return ERR_CAST(shmem);
> >>  
> >>  	shmem->sgt = sgt;
> >> +	shmem->imported_sgt = true;  
> > 
> > 
> > I feel like adding more fields that can be used to do the is_imported()
> > check is going to be even more confusing. Can we instead have
> > 
> > 	/* drm_gem_shmem_prime_import_sg_table() can be called from a
> > 	 * driver specific ->import_sg_table() implementations that
> > 	 * have extra failable initialization steps. Assign
> > 	 * drm_gem_object::import_attach here (even though it's
> > 	 * assigned in drm_gem_prime_import_dev()), so we don't end up
> > 	 * with driver error paths calling drm_gem_shmem_free() with an
> > 	 * imported sg_table assigned to drm_gem_shmem_object::sgt and
> > 	 * drm_gem_object::import_attach left uninitialized.
> > 	 */
> > 	shmem->base.import_attach = attach;
> > 
> > here?  
> 
> AFAICT, this is not going to work because obj->import_attach will be
> released by drm_prime core by the time drm_gem_shmem_free() is invoked
> and drm_gem_shmem_free() uses obj->import_attach as well.

How can this happen? If something wrong happens in the driver-specific
->gem_prime_import_sg_table() implementation, drm_gem_shmem_free() will
be called before ->gem_prime_import_sg_table() returns, and the
attachment will only be released after that [1].

> I'll keep this
> patch around unless there will be other suggestions. To me the flag is
> good enough, I'll add a clarifying comment to the code in v16.

I really think this is a bad idea, for the same reasons I gave in my
reply to patch 2 (adding fields that need to be maintained when the
state can be inferred from other fields is error prone).

[1]https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/drm_prime.c#L958

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v15 17/23] drm/shmem-helper: Add and use drm_gem_shmem_resv_assert_held() helper
  2023-09-02 19:43         ` Dmitry Osipenko
@ 2023-09-04  8:36           ` Boris Brezillon
  0 siblings, 0 replies; 53+ messages in thread
From: Boris Brezillon @ 2023-09-04  8:36 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: David Airlie, Gerd Hoffmann, Gurchetan Singh, Chia-I Wu,
	Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Christian König, Qiang Yu, Steven Price,
	Emma Anholt, Melissa Wen, Will Deacon, Peter Zijlstra,
	Boqun Feng, Mark Rutland, dri-devel, linux-kernel, kernel,
	virtualization, intel-gfx

On Sat, 2 Sep 2023 22:43:02 +0300
Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:

> On 8/29/23 10:29, Boris Brezillon wrote:
> > On Tue, 29 Aug 2023 05:34:23 +0300
> > Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:
> >   
> >> On 8/28/23 13:12, Boris Brezillon wrote:  
> >>> On Sun, 27 Aug 2023 20:54:43 +0300
> >>> Dmitry Osipenko <dmitry.osipenko@collabora.com> wrote:
> >>>     
> >>>> In a preparation of adding drm-shmem memory shrinker, move all reservation
> >>>> locking lockdep checks to use new drm_gem_shmem_resv_assert_held() that
> >>>> will resolve spurious lockdep warning about wrong locking order vs
> >>>> fs_reclam code paths during freeing of shmem GEM, where lockdep isn't
> >>>> aware that it's impossible to have locking contention with the fs_reclam
> >>>> at this special time.
> >>>>
> >>>> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
> >>>> ---
> >>>>  drivers/gpu/drm/drm_gem_shmem_helper.c | 37 +++++++++++++++++---------
> >>>>  1 file changed, 25 insertions(+), 12 deletions(-)
> >>>>
> >>>> diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
> >>>> index d96fee3d6166..ca5da976aafa 100644
> >>>> --- a/drivers/gpu/drm/drm_gem_shmem_helper.c
> >>>> +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
> >>>> @@ -128,6 +128,23 @@ struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t
> >>>>  }
> >>>>  EXPORT_SYMBOL_GPL(drm_gem_shmem_create);
> >>>>  
> >>>> +static void drm_gem_shmem_resv_assert_held(struct drm_gem_shmem_object *shmem)
> >>>> +{
> >>>> +	/*
> >>>> +	 * Destroying the object is a special case.. drm_gem_shmem_free()
> >>>> +	 * calls many things that WARN_ON if the obj lock is not held.  But
> >>>> +	 * acquiring the obj lock in drm_gem_shmem_free() can cause a locking
> >>>> +	 * order inversion between reservation_ww_class_mutex and fs_reclaim.
> >>>> +	 *
> >>>> +	 * This deadlock is not actually possible, because no one should
> >>>> +	 * be already holding the lock when drm_gem_shmem_free() is called.
> >>>> +	 * Unfortunately lockdep is not aware of this detail.  So when the
> >>>> +	 * refcount drops to zero, we pretend it is already locked.
> >>>> +	 */
> >>>> +	if (kref_read(&shmem->base.refcount))
> >>>> +		drm_gem_shmem_resv_assert_held(shmem);
> >>>> +}
> >>>> +
> >>>>  /**
> >>>>   * drm_gem_shmem_free - Free resources associated with a shmem GEM object
> >>>>   * @shmem: shmem GEM object to free
> >>>> @@ -142,8 +159,6 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
> >>>>  	if (obj->import_attach) {
> >>>>  		drm_prime_gem_destroy(obj, shmem->sgt);
> >>>>  	} else if (!shmem->imported_sgt) {
> >>>> -		dma_resv_lock(shmem->base.resv, NULL);
> >>>> -
> >>>>  		drm_WARN_ON(obj->dev, kref_read(&shmem->vmap_use_count));
> >>>>  
> >>>>  		if (shmem->sgt) {
> >>>> @@ -156,8 +171,6 @@ void drm_gem_shmem_free(struct drm_gem_shmem_object *shmem)
> >>>>  			drm_gem_shmem_put_pages_locked(shmem);    
> >>>
> >>> AFAICT, drm_gem_shmem_put_pages_locked() is the only function that's
> >>> called in the free path and would complain about resv-lock not being
> >>> held. I think I'd feel more comfortable if we were adding a
> >>> drm_gem_shmem_free_pages() function that did everything
> >>> drm_gem_shmem_put_pages_locked() does except for the lock_held() check
> >>> and the refcount dec, and have it called here (and in
> >>> drm_gem_shmem_put_pages_locked()). This way we can keep using
> >>> dma_resv_assert_held() instead of having our own variant.    
> >>
> >> It's not only drm_gem_shmem_free_pages(), but any drm-shmem function
> >> that drivers may use in the GEM's freeing callback.
> >>
> >> For example, panfrost_gem_free_object() may unpin shmem BO and then do
> >> drm_gem_shmem_free().  
> > 
> > Is this really a valid use case? If the GEM refcount dropped to zero,
> > we should certainly not have pages_pin_count > 0 (thinking of vmap-ed
> > buffers that might disappear while kernel still has a pointer to the
> > CPU-mapped area). The only reason we have this
> > drm_gem_shmem_put_pages_locked() in drm_gem_shmem_free() is because of
> > this implicit ref hold by the sgt, and IMHO, we should be stricter and
> > check that pages_use_count == 1 when sgt != NULL and pages_use_count ==
> > 0 otherwise.
> > 
> > I actually think it's a good thing to try and catch any attempt to call
> > functions trying lock the resv in a path they're not supposed to. At
> > least we can decide whether these actions are valid or not in this
> > context, and provide dedicated helpers for the free path if they are.  
> 
> To me it's a valid use-case. I was going to do it for the virtio-gpu
> driver for a specific BO type that should be permanently pinned in
> memory. So I made the BO pinned in the virto_gpu's bo_create() and
> unpinned it from the virtio-gpu's gem->free(), this is a perfectly valid
> case to me. Though, in the end I switched to another approach that
> doesn't require to do the pinning in the virtio-gpu driver.

Not saying driver-specific gem_create() methods can't own an
implicit ref on pages, but not checking that pages_{use,ref}_count <=
max_implicit_refs means you leave an opportunity for pages ref leaks to
go unnoticed. If your driver has a pin_on_creation flag, it should get a
ref in the creation path, and release this ref in the gem_free() path,
before calling drm_gem_shmem_free(), so the shmem layer can still make
sure there's at most one implicit ref left (the one taken by the sgt
creation logic) in drm_gem_shmem_free().

^ permalink raw reply	[flat|nested] 53+ messages in thread

end of thread, other threads:[~2023-09-04  8:36 UTC | newest]

Thread overview: 53+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-27 17:54 [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Dmitry Osipenko
2023-08-27 17:54 ` [PATCH v15 01/23] drm/shmem-helper: Fix UAF in error path when freeing SGT of imported GEM Dmitry Osipenko
2023-08-28 11:16   ` Boris Brezillon
2023-09-02 18:15     ` Dmitry Osipenko
2023-09-04  8:01       ` Boris Brezillon
2023-08-27 17:54 ` [PATCH v15 02/23] drm/shmem-helper: Use flag for tracking page count bumped by get_pages_sgt() Dmitry Osipenko
2023-08-28 10:55   ` Boris Brezillon
2023-09-02 18:28     ` Dmitry Osipenko
2023-09-04  7:52       ` Boris Brezillon
2023-08-27 17:54 ` [PATCH v15 03/23] drm/gem: Change locked/unlocked postfix of drm_gem_v/unmap() function names Dmitry Osipenko
2023-08-28 11:25   ` Boris Brezillon
2023-08-27 17:54 ` [PATCH v15 04/23] drm/gem: Add _locked postfix to functions that have unlocked counterpart Dmitry Osipenko
2023-08-28 11:25   ` Boris Brezillon
2023-08-27 17:54 ` [PATCH v15 05/23] drm/v3d: Replace open-coded drm_gem_shmem_free() with drm_gem_object_put() Dmitry Osipenko
2023-08-27 17:54 ` [PATCH v15 06/23] drm/virtio: Replace " Dmitry Osipenko
2023-08-27 17:54 ` [PATCH v15 07/23] drm/shmem-helper: Make all exported symbols GPL Dmitry Osipenko
2023-08-27 17:54 ` [PATCH v15 08/23] drm/shmem-helper: Refactor locked/unlocked functions Dmitry Osipenko
2023-08-28 11:28   ` Boris Brezillon
2023-08-27 17:54 ` [PATCH v15 09/23] drm/shmem-helper: Remove obsoleted is_iomem test Dmitry Osipenko
2023-08-28 11:29   ` Boris Brezillon
2023-08-27 17:54 ` [PATCH v15 10/23] locking/refcount, kref: Add kref_put_ww_mutex() Dmitry Osipenko
2023-08-28  9:26   ` Boris Brezillon
2023-08-29  2:28     ` Dmitry Osipenko
2023-08-27 17:54 ` [PATCH v15 11/23] dma-resv: Add kref_put_dma_resv() Dmitry Osipenko
2023-08-28 10:21   ` Christian König
2023-08-27 17:54 ` [PATCH v15 12/23] drm/shmem-helper: Add and use pages_pin_count Dmitry Osipenko
2023-08-28  9:38   ` Boris Brezillon
2023-08-28 11:46   ` Boris Brezillon
2023-08-29  2:30     ` Dmitry Osipenko
2023-08-27 17:54 ` [PATCH v15 13/23] drm/shmem-helper: Use kref for pages_use_count Dmitry Osipenko
2023-08-27 17:54 ` [PATCH v15 14/23] drm/shmem-helper: Add and use lockless drm_gem_shmem_get_pages() Dmitry Osipenko
2023-08-27 17:54 ` [PATCH v15 15/23] drm/shmem-helper: Switch drm_gem_shmem_vmap/vunmap to use pin/unpin Dmitry Osipenko
2023-08-27 17:54 ` [PATCH v15 16/23] drm/shmem-helper: Use kref for vmap_use_count Dmitry Osipenko
2023-08-28 10:00   ` Boris Brezillon
2023-09-02 20:22     ` Dmitry Osipenko
2023-08-27 17:54 ` [PATCH v15 17/23] drm/shmem-helper: Add and use drm_gem_shmem_resv_assert_held() helper Dmitry Osipenko
2023-08-28 10:12   ` Boris Brezillon
2023-08-29  2:34     ` Dmitry Osipenko
2023-08-29  7:29       ` Boris Brezillon
2023-08-29  8:52         ` Christian König
2023-08-29  9:44           ` Boris Brezillon
2023-08-29 10:21             ` Boris Brezillon
2023-09-02 19:43         ` Dmitry Osipenko
2023-09-04  8:36           ` Boris Brezillon
2023-08-27 17:54 ` [PATCH v15 18/23] drm/shmem-helper: Add memory shrinker Dmitry Osipenko
2023-08-27 17:54 ` [PATCH v15 19/23] drm/shmem-helper: Export drm_gem_shmem_get_pages_sgt_locked() Dmitry Osipenko
2023-08-27 17:54 ` [PATCH v15 20/23] drm/virtio: Pin display framebuffer BO Dmitry Osipenko
2023-08-27 17:54 ` [PATCH v15 21/23] drm/virtio: Attach shmem BOs dynamically Dmitry Osipenko
2023-08-27 17:54 ` [PATCH v15 22/23] drm/virtio: Support memory shrinking Dmitry Osipenko
2023-08-27 17:54 ` [PATCH v15 23/23] drm/panfrost: Switch to generic memory shrinker Dmitry Osipenko
2023-08-28 14:37 ` [PATCH v15 00/23] Add generic memory shrinker to VirtIO-GPU and Panfrost DRM drivers Helen Mae Koike Fornazier
2023-08-28 15:24   ` Helen Mae Koike Fornazier
2023-08-29  2:36     ` Dmitry Osipenko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).