drm/shmem: Add madvise state and purge helpers
authorRob Herring <robh@kernel.org>
Mon, 5 Aug 2019 14:33:57 +0000 (08:33 -0600)
committerRob Herring <robh@kernel.org>
Thu, 8 Aug 2019 21:54:10 +0000 (15:54 -0600)
Add support to the shmem GEM helpers for tracking madvise state and
purging pages. This is based on the msm implementation.

The BO provides a list_head, but the list management is handled outside
of the shmem helpers as there are different locking requirements.

Cc: Tomeu Vizoso <tomeu.vizoso@collabora.com>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: Maxime Ripard <maxime.ripard@bootlin.com>
Cc: Sean Paul <sean@poorly.run>
Cc: David Airlie <airlied@linux.ie>
Cc: Daniel Vetter <daniel@ffwll.ch>
Cc: Eric Anholt <eric@anholt.net>
Acked-by: Acked-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
Signed-off-by: Rob Herring <robh@kernel.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20190805143358.21245-1-robh@kernel.org
drivers/gpu/drm/drm_gem_shmem_helper.c
include/drm/drm_gem_shmem_helper.h

index 2f64667ac8055a7dec6f92fe5fa0ab0cd4b31290..4b442576de1c61624bf201fdc85baddadf13457b 100644 (file)
@@ -75,6 +75,7 @@ struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t
        shmem = to_drm_gem_shmem_obj(obj);
        mutex_init(&shmem->pages_lock);
        mutex_init(&shmem->vmap_lock);
+       INIT_LIST_HEAD(&shmem->madv_list);
 
        /*
         * Our buffers are kept pinned, so allocating them
@@ -362,6 +363,62 @@ drm_gem_shmem_create_with_handle(struct drm_file *file_priv,
 }
 EXPORT_SYMBOL(drm_gem_shmem_create_with_handle);
 
+/* Update madvise status, returns true if not purged, else
+ * false or -errno.
+ */
+int drm_gem_shmem_madvise(struct drm_gem_object *obj, int madv)
+{
+       struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
+
+       mutex_lock(&shmem->pages_lock);
+
+       if (shmem->madv >= 0)
+               shmem->madv = madv;
+
+       madv = shmem->madv;
+
+       mutex_unlock(&shmem->pages_lock);
+
+       return (madv >= 0);
+}
+EXPORT_SYMBOL(drm_gem_shmem_madvise);
+
+void drm_gem_shmem_purge_locked(struct drm_gem_object *obj)
+{
+       struct drm_device *dev = obj->dev;
+       struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
+
+       WARN_ON(!drm_gem_shmem_is_purgeable(shmem));
+
+       drm_gem_shmem_put_pages_locked(shmem);
+
+       shmem->madv = -1;
+
+       drm_vma_node_unmap(&obj->vma_node, dev->anon_inode->i_mapping);
+       drm_gem_free_mmap_offset(obj);
+
+       /* Our goal here is to return as much of the memory as
+        * is possible back to the system as we are called from OOM.
+        * To do this we must instruct the shmfs to drop all of its
+        * backing pages, *now*.
+        */
+       shmem_truncate_range(file_inode(obj->filp), 0, (loff_t)-1);
+
+       invalidate_mapping_pages(file_inode(obj->filp)->i_mapping,
+                       0, (loff_t)-1);
+}
+EXPORT_SYMBOL(drm_gem_shmem_purge_locked);
+
+void drm_gem_shmem_purge(struct drm_gem_object *obj)
+{
+       struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
+
+       mutex_lock(&shmem->pages_lock);
+       drm_gem_shmem_purge_locked(obj);
+       mutex_unlock(&shmem->pages_lock);
+}
+EXPORT_SYMBOL(drm_gem_shmem_purge);
+
 /**
  * drm_gem_shmem_dumb_create - Create a dumb shmem buffer object
  * @file: DRM file structure to create the dumb buffer for
index 038b6d3134471b363234bcd2635209ae26ae8d0e..ce1600fdfc3ecd78d413d2c10f5f7e49ff185c65 100644 (file)
@@ -44,6 +44,9 @@ struct drm_gem_shmem_object {
         */
        unsigned int pages_use_count;
 
+       int madv;
+       struct list_head madv_list;
+
        /**
         * @pages_mark_dirty_on_put:
         *
@@ -121,6 +124,18 @@ void drm_gem_shmem_unpin(struct drm_gem_object *obj);
 void *drm_gem_shmem_vmap(struct drm_gem_object *obj);
 void drm_gem_shmem_vunmap(struct drm_gem_object *obj, void *vaddr);
 
+int drm_gem_shmem_madvise(struct drm_gem_object *obj, 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 &&
+               !shmem->base.dma_buf && !shmem->base.import_attach;
+}
+
+void drm_gem_shmem_purge_locked(struct drm_gem_object *obj);
+void drm_gem_shmem_purge(struct drm_gem_object *obj);
+
 struct drm_gem_shmem_object *
 drm_gem_shmem_create_with_handle(struct drm_file *file_priv,
                                 struct drm_device *dev, size_t size,