diff mbox

tests/gem_reset_stats: add close-pending-fork

Message ID 1386167949-10162-1-git-send-email-mika.kuoppala@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Mika Kuoppala Dec. 4, 2013, 2:39 p.m. UTC
From: Mika Kuoppala <mika.kuoppala@linux.intel.com>

This triggers use after free oops on request->batch_obj when
going through the rings and setting reset status on requests,
after a gpu hang.

v2: Streamlined the test and added comments (Daniel)

Signed-off-by: Mika Kuoppala <mika.kuoppala@intel.com>
---
 tests/gem_reset_stats.c |   62 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)

Comments

Daniel Vetter Dec. 4, 2013, 3:48 p.m. UTC | #1
On Wed, Dec 04, 2013 at 04:39:09PM +0200, Mika Kuoppala wrote:
> From: Mika Kuoppala <mika.kuoppala@linux.intel.com>
> 
> This triggers use after free oops on request->batch_obj when
> going through the rings and setting reset status on requests,
> after a gpu hang.
> 
> v2: Streamlined the test and added comments (Daniel)
> 
> Signed-off-by: Mika Kuoppala <mika.kuoppala@intel.com>
> ---
>  tests/gem_reset_stats.c |   62 +++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 62 insertions(+)
> 
> diff --git a/tests/gem_reset_stats.c b/tests/gem_reset_stats.c
> index 6c22bce..095b14b 100644
> --- a/tests/gem_reset_stats.c
> +++ b/tests/gem_reset_stats.c
> @@ -25,6 +25,7 @@
>   *
>   */
>  
> +#define _GNU_SOURCE
>  #include <unistd.h>
>  #include <stdlib.h>
>  #include <stdio.h>
> @@ -36,6 +37,7 @@
>  #include <sys/ioctl.h>
>  #include <sys/mman.h>
>  #include <time.h>
> +#include <signal.h>
>  
>  #include "i915_drm.h"
>  #include "intel_bufmgr.h"
> @@ -637,6 +639,63 @@ static void test_close_pending(void)
>  	close(fd);
>  }
>  
> +static void test_close_pending_fork(void)
> +{
> +	int pid;
> +	int fd, h;
> +
> +	fd = drm_open_any();
> +	igt_assert(fd >= 0);
> +
> +	assert_reset_status(fd, 0, RS_NO_ERROR);
> +
> +	h = inject_hang(fd, 0);
> +	igt_assert(h >= 0);
> +
> +	sleep(1);
> +
> +	/* Avoid helpers as we need to kill the child
> +	 * without any extra signal handling on behalf of
> +	 * lib/drmtest.c
> +	 */
> +	pid = fork();
> +	if (pid == 0) {
> +		/* Not first drm_open_any() so we need to do
> +		 * gem_quiescent_gpu() explicitly, as it is the
> +		 * key component to trigger the oops
> +		 */

I've added a small comment here explaining what exactly is the magic
ingredient in quiescent_gpu and applied and pushed the patch.

But on second thoughs it's a bit fragile to depend upon the test library
behaviour in such a way. I think it's better to copy-paste the code in
quiescent_gpu to this file to make sure we never accidentally change it
and end up breaking this test.

When doing that we could also try to run the empty batch on all rings in
reverse order, just in case someone reorders a list somewhere. That should
make the testcase more robust at catching issues.
-Daniel

> +		const int fd2 = drm_open_any();
> +		igt_assert(fd2 >= 0);
> +
> +		/* This adds same batch on each ring */
> +		gem_quiescent_gpu(fd2);
> +
> +		close(fd2);
> +		return;
> +	} else {
> +		igt_assert(pid > 0);
> +		sleep(1);
> +
> +		/* Kill the child to reduce refcounts on
> +		   batch_objs */
> +		kill(pid, SIGKILL);
> +	}
> +
> +	gem_close(fd, h);
> +	close(fd);
> +
> +	/* Then we just wait on hang to happen */
> +	fd = drm_open_any();
> +	igt_assert(fd >= 0);
> +
> +	h = exec_valid(fd, 0);
> +	igt_assert(h >= 0);
> +
> +	gem_sync(fd, h);
> +	gem_close(fd, h);
> +	close(fd);
> +}
> +
>  static void drop_root(void)
>  {
>  	igt_assert(getuid() == 0);
> @@ -837,6 +896,9 @@ igt_main
>  	igt_subtest("close-pending")
>  		test_close_pending();
>  
> +	igt_subtest("close-pending-fork")
> +		test_close_pending_fork();
> +
>  	igt_subtest("params")
>  		test_params();
>  }
> -- 
> 1.7.9.5
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
diff mbox

Patch

diff --git a/tests/gem_reset_stats.c b/tests/gem_reset_stats.c
index 6c22bce..095b14b 100644
--- a/tests/gem_reset_stats.c
+++ b/tests/gem_reset_stats.c
@@ -25,6 +25,7 @@ 
  *
  */
 
+#define _GNU_SOURCE
 #include <unistd.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -36,6 +37,7 @@ 
 #include <sys/ioctl.h>
 #include <sys/mman.h>
 #include <time.h>
+#include <signal.h>
 
 #include "i915_drm.h"
 #include "intel_bufmgr.h"
@@ -637,6 +639,63 @@  static void test_close_pending(void)
 	close(fd);
 }
 
+static void test_close_pending_fork(void)
+{
+	int pid;
+	int fd, h;
+
+	fd = drm_open_any();
+	igt_assert(fd >= 0);
+
+	assert_reset_status(fd, 0, RS_NO_ERROR);
+
+	h = inject_hang(fd, 0);
+	igt_assert(h >= 0);
+
+	sleep(1);
+
+	/* Avoid helpers as we need to kill the child
+	 * without any extra signal handling on behalf of
+	 * lib/drmtest.c
+	 */
+	pid = fork();
+	if (pid == 0) {
+		/* Not first drm_open_any() so we need to do
+		 * gem_quiescent_gpu() explicitly, as it is the
+		 * key component to trigger the oops
+		 */
+		const int fd2 = drm_open_any();
+		igt_assert(fd2 >= 0);
+
+		/* This adds same batch on each ring */
+		gem_quiescent_gpu(fd2);
+
+		close(fd2);
+		return;
+	} else {
+		igt_assert(pid > 0);
+		sleep(1);
+
+		/* Kill the child to reduce refcounts on
+		   batch_objs */
+		kill(pid, SIGKILL);
+	}
+
+	gem_close(fd, h);
+	close(fd);
+
+	/* Then we just wait on hang to happen */
+	fd = drm_open_any();
+	igt_assert(fd >= 0);
+
+	h = exec_valid(fd, 0);
+	igt_assert(h >= 0);
+
+	gem_sync(fd, h);
+	gem_close(fd, h);
+	close(fd);
+}
+
 static void drop_root(void)
 {
 	igt_assert(getuid() == 0);
@@ -837,6 +896,9 @@  igt_main
 	igt_subtest("close-pending")
 		test_close_pending();
 
+	igt_subtest("close-pending-fork")
+		test_close_pending_fork();
+
 	igt_subtest("params")
 		test_params();
 }