Skip to content

Commit

Permalink
drm/i915: Test exhaustion of the mmap space
Browse files Browse the repository at this point in the history
An unlikely error condition that we can simulate by stealing most of
the range before trying to insert new objects.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Matthew Auld <matthew.auld@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20170213171558.20942-20-chris@chris-wilson.co.uk
  • Loading branch information
Chris Wilson committed Feb 13, 2017
1 parent 48d8981 commit 3d81d58
Showing 1 changed file with 138 additions and 0 deletions.
138 changes: 138 additions & 0 deletions drivers/gpu/drm/i915/selftests/i915_gem_object.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "../i915_selftest.h"

#include "mock_gem_device.h"
#include "huge_gem_object.h"

static int igt_gem_object(void *arg)
{
Expand Down Expand Up @@ -432,6 +433,142 @@ next_tiling: ;
return err;
}

static int make_obj_busy(struct drm_i915_gem_object *obj)
{
struct drm_i915_private *i915 = to_i915(obj->base.dev);
struct drm_i915_gem_request *rq;
struct i915_vma *vma;
int err;

vma = i915_vma_instance(obj, &i915->ggtt.base, NULL);
if (IS_ERR(vma))
return PTR_ERR(vma);

err = i915_vma_pin(vma, 0, 0, PIN_USER);
if (err)
return err;

rq = i915_gem_request_alloc(i915->engine[RCS], i915->kernel_context);
if (IS_ERR(rq)) {
i915_vma_unpin(vma);
return PTR_ERR(rq);
}

i915_vma_move_to_active(vma, rq, 0);
i915_add_request(rq);

i915_gem_object_set_active_reference(obj);
i915_vma_unpin(vma);
return 0;
}

static bool assert_mmap_offset(struct drm_i915_private *i915,
unsigned long size,
int expected)
{
struct drm_i915_gem_object *obj;
int err;

obj = i915_gem_object_create_internal(i915, size);
if (IS_ERR(obj))
return PTR_ERR(obj);

err = i915_gem_object_create_mmap_offset(obj);
i915_gem_object_put(obj);

return err == expected;
}

static int igt_mmap_offset_exhaustion(void *arg)
{
struct drm_i915_private *i915 = arg;
struct drm_mm *mm = &i915->drm.vma_offset_manager->vm_addr_space_mm;
struct drm_i915_gem_object *obj;
struct drm_mm_node resv, *hole;
u64 hole_start, hole_end;
int loop, err;

/* Trim the device mmap space to only a page */
memset(&resv, 0, sizeof(resv));
drm_mm_for_each_hole(hole, mm, hole_start, hole_end) {
resv.start = hole_start;
resv.size = hole_end - hole_start - 1; /* PAGE_SIZE units */
err = drm_mm_reserve_node(mm, &resv);
if (err) {
pr_err("Failed to trim VMA manager, err=%d\n", err);
return err;
}
break;
}

/* Just fits! */
if (!assert_mmap_offset(i915, PAGE_SIZE, 0)) {
pr_err("Unable to insert object into single page hole\n");
err = -EINVAL;
goto out;
}

/* Too large */
if (!assert_mmap_offset(i915, 2*PAGE_SIZE, -ENOSPC)) {
pr_err("Unexpectedly succeeded in inserting too large object into single page hole\n");
err = -EINVAL;
goto out;
}

/* Fill the hole, further allocation attempts should then fail */
obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
if (IS_ERR(obj)) {
err = PTR_ERR(obj);
goto out;
}

err = i915_gem_object_create_mmap_offset(obj);
if (err) {
pr_err("Unable to insert object into reclaimed hole\n");
goto err_obj;
}

if (!assert_mmap_offset(i915, PAGE_SIZE, -ENOSPC)) {
pr_err("Unexpectedly succeeded in inserting object into no holes!\n");
err = -EINVAL;
goto err_obj;
}

i915_gem_object_put(obj);

/* Now fill with busy dead objects that we expect to reap */
for (loop = 0; loop < 3; loop++) {
obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
if (IS_ERR(obj)) {
err = PTR_ERR(obj);
goto out;
}

mutex_lock(&i915->drm.struct_mutex);
err = make_obj_busy(obj);
mutex_unlock(&i915->drm.struct_mutex);
if (err) {
pr_err("[loop %d] Failed to busy the object\n", loop);
goto err_obj;
}

GEM_BUG_ON(!i915_gem_object_is_active(obj));
err = i915_gem_object_create_mmap_offset(obj);
if (err) {
pr_err("[loop %d] i915_gem_object_create_mmap_offset failed with err=%d\n",
loop, err);
goto out;
}
}

out:
drm_mm_remove_node(&resv);
return err;
err_obj:
i915_gem_object_put(obj);
goto out;
}

int i915_gem_object_mock_selftests(void)
{
static const struct i915_subtest tests[] = {
Expand All @@ -456,6 +593,7 @@ int i915_gem_object_live_selftests(struct drm_i915_private *i915)
static const struct i915_subtest tests[] = {
SUBTEST(igt_gem_huge),
SUBTEST(igt_partial_tiling),
SUBTEST(igt_mmap_offset_exhaustion),
};

return i915_subtests(tests, i915);
Expand Down

0 comments on commit 3d81d58

Please sign in to comment.