aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2017-06-09 07:03:46 -0400
committerJani Nikula <jani.nikula@intel.com>2017-06-19 04:19:58 -0400
commitb8d5a9ccfba5fc084b50b00b9f5b587a8e64b72c (patch)
tree833a0eb138c5ce31ee7ce9ed8a43845efa10571b
parenta21ef715fbb8210c50b1d684145f8acdf2339596 (diff)
drm/i915: Encourage our shrinker more when our shmemfs allocations fails
Commit 24f8e00a8a2e ("drm/i915: Prefer to report ENOMEM rather than incur the oom for gfx allocations") made the bold decision to try and avoid the oomkiller by reporting -ENOMEM to userspace if our allocation failed after attempting to free enough buffer objects. In short, it appears we were giving up too easily (even before we start wondering if one pass of reclaim is as strong as we would like). Part of the problem is that if we only shrink just enough pages for our expected allocation, the likelihood of those pages becoming available to us is less than 100% To counter-act that we ask for twice the number of pages to be made available. Furthermore, we allow the shrinker to pull pages from the active list in later passes. v2: Be a little more cautious in paging out gfx buffers, and leave that to a more balanced approach from shrink_slab(). Important when combined with "drm/i915: Start writeback from the shrinker" as anything shrunk is immediately swapped out and so should be more conservative. Fixes: 24f8e00a8a2e ("drm/i915: Prefer to report ENOMEM rather than incur the oom for gfx allocations") Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/20170609110350.1767-1-chris@chris-wilson.co.uk (cherry picked from commit 4846bf0ca8cb4304dde6140eff33a92b3fe8ef24) Signed-off-by: Jani Nikula <jani.nikula@intel.com>
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c50
1 files changed, 29 insertions, 21 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 462031cbd77f..c93f27b981f5 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -2285,8 +2285,8 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
2285 struct page *page; 2285 struct page *page;
2286 unsigned long last_pfn = 0; /* suppress gcc warning */ 2286 unsigned long last_pfn = 0; /* suppress gcc warning */
2287 unsigned int max_segment; 2287 unsigned int max_segment;
2288 gfp_t noreclaim;
2288 int ret; 2289 int ret;
2289 gfp_t gfp;
2290 2290
2291 /* Assert that the object is not currently in any GPU domain. As it 2291 /* Assert that the object is not currently in any GPU domain. As it
2292 * wasn't in the GTT, there shouldn't be any way it could have been in 2292 * wasn't in the GTT, there shouldn't be any way it could have been in
@@ -2315,22 +2315,31 @@ rebuild_st:
2315 * Fail silently without starting the shrinker 2315 * Fail silently without starting the shrinker
2316 */ 2316 */
2317 mapping = obj->base.filp->f_mapping; 2317 mapping = obj->base.filp->f_mapping;
2318 gfp = mapping_gfp_constraint(mapping, ~(__GFP_IO | __GFP_RECLAIM)); 2318 noreclaim = mapping_gfp_constraint(mapping,
2319 gfp |= __GFP_NORETRY | __GFP_NOWARN; 2319 ~(__GFP_IO | __GFP_RECLAIM));
2320 noreclaim |= __GFP_NORETRY | __GFP_NOWARN;
2321
2320 sg = st->sgl; 2322 sg = st->sgl;
2321 st->nents = 0; 2323 st->nents = 0;
2322 for (i = 0; i < page_count; i++) { 2324 for (i = 0; i < page_count; i++) {
2323 page = shmem_read_mapping_page_gfp(mapping, i, gfp); 2325 const unsigned int shrink[] = {
2324 if (unlikely(IS_ERR(page))) { 2326 I915_SHRINK_BOUND | I915_SHRINK_UNBOUND | I915_SHRINK_PURGEABLE,
2325 i915_gem_shrink(dev_priv, 2327 0,
2326 page_count, 2328 }, *s = shrink;
2327 I915_SHRINK_BOUND | 2329 gfp_t gfp = noreclaim;
2328 I915_SHRINK_UNBOUND | 2330
2329 I915_SHRINK_PURGEABLE); 2331 do {
2330 page = shmem_read_mapping_page_gfp(mapping, i, gfp); 2332 page = shmem_read_mapping_page_gfp(mapping, i, gfp);
2331 } 2333 if (likely(!IS_ERR(page)))
2332 if (unlikely(IS_ERR(page))) { 2334 break;
2333 gfp_t reclaim; 2335
2336 if (!*s) {
2337 ret = PTR_ERR(page);
2338 goto err_sg;
2339 }
2340
2341 i915_gem_shrink(dev_priv, 2 * page_count, *s++);
2342 cond_resched();
2334 2343
2335 /* We've tried hard to allocate the memory by reaping 2344 /* We've tried hard to allocate the memory by reaping
2336 * our own buffer, now let the real VM do its job and 2345 * our own buffer, now let the real VM do its job and
@@ -2340,15 +2349,13 @@ rebuild_st:
2340 * defer the oom here by reporting the ENOMEM back 2349 * defer the oom here by reporting the ENOMEM back
2341 * to userspace. 2350 * to userspace.
2342 */ 2351 */
2343 reclaim = mapping_gfp_mask(mapping); 2352 if (!*s) {
2344 reclaim |= __GFP_NORETRY; /* reclaim, but no oom */ 2353 /* reclaim and warn, but no oom */
2345 2354 gfp = mapping_gfp_mask(mapping);
2346 page = shmem_read_mapping_page_gfp(mapping, i, reclaim); 2355 gfp |= __GFP_NORETRY;
2347 if (IS_ERR(page)) {
2348 ret = PTR_ERR(page);
2349 goto err_sg;
2350 } 2356 }
2351 } 2357 } while (1);
2358
2352 if (!i || 2359 if (!i ||
2353 sg->length >= max_segment || 2360 sg->length >= max_segment ||
2354 page_to_pfn(page) != last_pfn + 1) { 2361 page_to_pfn(page) != last_pfn + 1) {
@@ -4222,6 +4229,7 @@ i915_gem_object_create(struct drm_i915_private *dev_priv, u64 size)
4222 4229
4223 mapping = obj->base.filp->f_mapping; 4230 mapping = obj->base.filp->f_mapping;
4224 mapping_set_gfp_mask(mapping, mask); 4231 mapping_set_gfp_mask(mapping, mask);
4232 GEM_BUG_ON(!(mapping_gfp_mask(mapping) & __GFP_RECLAIM));
4225 4233
4226 i915_gem_object_init(obj, &i915_gem_object_ops); 4234 i915_gem_object_init(obj, &i915_gem_object_ops);
4227 4235