All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/3] drm/i915: Include bound and active pages in the count of shrinkable objects
@ 2014-02-21 18:05 Chris Wilson
  2014-02-21 18:05 ` [PATCH 2/3] drm/i915: Safely acquire the struct_mutex in our mem shrinker Chris Wilson
  2014-02-21 18:05 ` [PATCH 3/3] drm/i915: Writeback our pages under memory pressure Chris Wilson
  0 siblings, 2 replies; 3+ messages in thread
From: Chris Wilson @ 2014-02-21 18:05 UTC (permalink / raw)
  To: intel-gfx

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_gem.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 3618bb0cda0a..d0cd9df4c1f7 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -4886,6 +4886,19 @@ static bool mutex_is_locked_by(struct mutex *mutex, struct task_struct *task)
 #endif
 }
 
+static int num_vma_bound(struct drm_i915_gem_object *obj)
+{
+	struct i915_vma *vma;
+	int count = 0;
+
+	list_for_each_entry(vma, &obj->vma_list, vma_link)
+		if (drm_mm_node_allocated(&vma->node))
+			count++;
+
+	return count;
+
+}
+
 static unsigned long
 i915_gem_inactive_count(struct shrinker *shrinker, struct shrink_control *sc)
 {
@@ -4917,7 +4930,8 @@ i915_gem_inactive_count(struct shrinker *shrinker, struct shrink_control *sc)
 		if (obj->active)
 			continue;
 
-		if (!i915_gem_obj_is_pinned(obj) && obj->pages_pin_count == 0)
+		if (!i915_gem_obj_is_pinned(obj) &&
+		    obj->pages_pin_count == num_vma_bound(obj))
 			count += obj->base.size >> PAGE_SHIFT;
 	}
 
-- 
1.9.0

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

* [PATCH 2/3] drm/i915: Safely acquire the struct_mutex in our mem shrinker
  2014-02-21 18:05 [PATCH 1/3] drm/i915: Include bound and active pages in the count of shrinkable objects Chris Wilson
@ 2014-02-21 18:05 ` Chris Wilson
  2014-02-21 18:05 ` [PATCH 3/3] drm/i915: Writeback our pages under memory pressure Chris Wilson
  1 sibling, 0 replies; 3+ messages in thread
From: Chris Wilson @ 2014-02-21 18:05 UTC (permalink / raw)
  To: intel-gfx

Under memory pressure it is important that we strive to unpin some of
our objects so that their backing pages can be swapped out. However, we
have to avoid recursion in struct_mutex and also make sure that we
safely wait upon the device and driver. The first part is done by first
using a trylock and checking for recursion, but the latter was ignored.
However, we can use i915_mutex_interruptible() for a safe locking
strategy that should prevent deadlocks.
---
 drivers/gpu/drm/i915/i915_gem.c | 49 +++++++++++++++++++++--------------------
 1 file changed, 25 insertions(+), 24 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index d0cd9df4c1f7..3a620779057c 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -4873,13 +4873,28 @@ int i915_gem_open(struct drm_device *dev, struct drm_file *file)
 	return ret;
 }
 
-static bool mutex_is_locked_by(struct mutex *mutex, struct task_struct *task)
+static bool
+i915_gem_shrinker_lock(struct drm_device *dev, bool *unlock)
 {
-	if (!mutex_is_locked(mutex))
-		return false;
+	*unlock = true;
+	if (mutex_trylock(&dev->struct_mutex))
+		return true;
 
 #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_MUTEXES)
-	return mutex->owner == task;
+	if (dev->struct_mutex.owner == current) {
+		if (to_i915(dev)->mm.shrinker_no_lock_stealing)
+			return false;
+
+		*unlock = false;
+	} else {
+		/* lockdep classifies this as an ABBA deadlock,
+		 * but given the lock stealing above this is
+		 * safe. So treat this a separate subclass.
+		 */
+		mutex_lock_nested(&dev->struct_mutex, 1);
+	}
+
+	return true;
 #else
 	/* Since UP may be pre-empted, we cannot assume that we own the lock */
 	return false;
@@ -4908,18 +4923,11 @@ i915_gem_inactive_count(struct shrinker *shrinker, struct shrink_control *sc)
 			     mm.inactive_shrinker);
 	struct drm_device *dev = dev_priv->dev;
 	struct drm_i915_gem_object *obj;
-	bool unlock = true;
 	unsigned long count;
+	bool unlock;
 
-	if (!mutex_trylock(&dev->struct_mutex)) {
-		if (!mutex_is_locked_by(&dev->struct_mutex, current))
-			return 0;
-
-		if (dev_priv->mm.shrinker_no_lock_stealing)
-			return 0;
-
-		unlock = false;
-	}
+	if (!i915_gem_shrinker_lock(dev, &unlock))
+		return 0;
 
 	count = 0;
 	list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list)
@@ -5012,17 +5020,10 @@ i915_gem_inactive_scan(struct shrinker *shrinker, struct shrink_control *sc)
 			     mm.inactive_shrinker);
 	struct drm_device *dev = dev_priv->dev;
 	unsigned long freed;
-	bool unlock = true;
-
-	if (!mutex_trylock(&dev->struct_mutex)) {
-		if (!mutex_is_locked_by(&dev->struct_mutex, current))
-			return SHRINK_STOP;
+	bool unlock;
 
-		if (dev_priv->mm.shrinker_no_lock_stealing)
-			return SHRINK_STOP;
-
-		unlock = false;
-	}
+	if (!i915_gem_shrinker_lock(dev, &unlock))
+		return SHRINK_STOP;
 
 	freed = i915_gem_purge(dev_priv, sc->nr_to_scan);
 	if (freed < sc->nr_to_scan)
-- 
1.9.0

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

* [PATCH 3/3] drm/i915: Writeback our pages under memory pressure
  2014-02-21 18:05 [PATCH 1/3] drm/i915: Include bound and active pages in the count of shrinkable objects Chris Wilson
  2014-02-21 18:05 ` [PATCH 2/3] drm/i915: Safely acquire the struct_mutex in our mem shrinker Chris Wilson
@ 2014-02-21 18:05 ` Chris Wilson
  1 sibling, 0 replies; 3+ messages in thread
From: Chris Wilson @ 2014-02-21 18:05 UTC (permalink / raw)
  To: intel-gfx

Try to flush out dirty pages into the swapcache (and from there into the
swapfile) when under memory pressure and forced to drop GEM objects from
memory.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_gem.c | 48 ++++++++++++++++++++++++++++++-----------
 1 file changed, 36 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 3a620779057c..a728c765c416 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -34,6 +34,7 @@
 #include <linux/shmem_fs.h>
 #include <linux/slab.h>
 #include <linux/swap.h>
+#include <linux/writeback.h>
 #include <linux/pci.h>
 #include <linux/dma-buf.h>
 
@@ -60,7 +61,6 @@ static unsigned long i915_gem_inactive_scan(struct shrinker *shrinker,
 					    struct shrink_control *sc);
 static unsigned long i915_gem_purge(struct drm_i915_private *dev_priv, long target);
 static unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv);
-static void i915_gem_object_truncate(struct drm_i915_gem_object *obj);
 
 static bool cpu_cache_is_coherent(struct drm_device *dev,
 				  enum i915_cache_level level)
@@ -1666,12 +1666,16 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
 	return i915_gem_mmap_gtt(file, dev, args->handle, &args->offset);
 }
 
+static inline int
+i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj)
+{
+	return obj->madv == I915_MADV_DONTNEED;
+}
+
 /* Immediately discard the backing storage */
 static void
 i915_gem_object_truncate(struct drm_i915_gem_object *obj)
 {
-	struct inode *inode;
-
 	i915_gem_object_free_mmap_offset(obj);
 
 	if (obj->base.filp == NULL)
@@ -1682,16 +1686,35 @@ i915_gem_object_truncate(struct drm_i915_gem_object *obj)
 	 * To do this we must instruct the shmfs to drop all of its
 	 * backing pages, *now*.
 	 */
-	inode = file_inode(obj->base.filp);
-	shmem_truncate_range(inode, 0, (loff_t)-1);
-
+	shmem_truncate_range(file_inode(obj->base.filp), 0, (loff_t)-1);
 	obj->madv = __I915_MADV_PURGED;
 }
 
-static inline int
-i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj)
-{
-	return obj->madv == I915_MADV_DONTNEED;
+/* Try to discard unwanted pages */
+static void
+i915_gem_object_writeback(struct drm_i915_gem_object *obj)
+{
+	struct writeback_control wbc = {
+		.nr_to_write = LONG_MAX,
+		.sync_mode = WB_SYNC_NONE,
+		.range_start = 0,
+		.range_end = LLONG_MAX,
+	};
+	struct address_space *mapping;
+
+	switch (obj->madv) {
+	case I915_MADV_DONTNEED:
+		i915_gem_object_truncate(obj);
+	case __I915_MADV_PURGED:
+		return;
+	}
+
+	if (obj->base.filp == NULL)
+		return;
+
+	mapping = file_inode(obj->base.filp)->i_mapping,
+	generic_writepages(mapping, &wbc);
+	invalidate_mapping_pages(mapping, 0, (loff_t)-1);
 }
 
 static void
@@ -1756,8 +1779,7 @@ i915_gem_object_put_pages(struct drm_i915_gem_object *obj)
 	ops->put_pages(obj);
 	obj->pages = NULL;
 
-	if (i915_gem_object_is_purgeable(obj))
-		i915_gem_object_truncate(obj);
+	i915_gem_object_writeback(obj);
 
 	return 0;
 }
@@ -4175,6 +4197,8 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
 
 	if (WARN_ON(obj->pages_pin_count))
 		obj->pages_pin_count = 0;
+	if (obj->madv != __I915_MADV_PURGED)
+		obj->madv = I915_MADV_DONTNEED;
 	i915_gem_object_put_pages(obj);
 	i915_gem_object_free_mmap_offset(obj);
 	i915_gem_object_release_stolen(obj);
-- 
1.9.0

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

end of thread, other threads:[~2014-02-21 18:05 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-21 18:05 [PATCH 1/3] drm/i915: Include bound and active pages in the count of shrinkable objects Chris Wilson
2014-02-21 18:05 ` [PATCH 2/3] drm/i915: Safely acquire the struct_mutex in our mem shrinker Chris Wilson
2014-02-21 18:05 ` [PATCH 3/3] drm/i915: Writeback our pages under memory pressure Chris Wilson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.