[2/2] tests: Introduce drv_cgroup

Submitted by Matt Roper on March 6, 2018, 11:49 p.m.

Details

Message ID 20180306234910.6652-2-matthew.d.roper@intel.com
State New
Headers show
Series "Series without cover letter" ( rev: 2 ) in IGT (deprecated)

Not browsing as part of any series.

Commit Message

Matt Roper March 6, 2018, 11:49 p.m.
drv_cgroup exercises both valid and invalid usage of the i915 cgroup
parameter ioctl.

Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
---
 tests/Makefile.sources |   1 +
 tests/drv_cgroup.c     | 236 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 237 insertions(+)
 create mode 100644 tests/drv_cgroup.c

Patch hide | download patch | download mbox

diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 4a81ac4a..acba3f98 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -37,6 +37,7 @@  TESTS_progs = \
 	drm_vma_limiter_cached \
 	drm_vma_limiter_cpu \
 	drm_vma_limiter_gtt \
+	drv_cgroup \
 	drv_getparams_basic \
 	drv_hangman \
 	drv_missed_irq \
diff --git a/tests/drv_cgroup.c b/tests/drv_cgroup.c
new file mode 100644
index 00000000..6cc49539
--- /dev/null
+++ b/tests/drv_cgroup.c
@@ -0,0 +1,236 @@ 
+/*
+ * Copyright © 2018 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include "igt.h"
+#include "igt_debugfs.h"
+#include "igt_aux.h"
+#include "igt_kmod.h"
+#include "igt_sysfs.h"
+#include "igt_core.h"
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <signal.h>
+#include <stdio.h>
+#include <linux/limits.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+
+/* libdrm support is not yet upstream, so duplicate defs here for now */
+
+struct INTERNAL_drm_i915_cgroup_param {
+	__s32 cgroup_fd;
+	__u32 flags;
+	__u64 param;
+#define I915_CGROUP_PARAM_PRIORITY_OFFSET       0x1
+	__s64 value;
+};
+
+#define INTERNAL_IOCTL_I915_CGROUP_SETPARAM  \
+	DRM_IOW(DRM_COMMAND_BASE + 0x39, struct INTERNAL_drm_i915_cgroup_param)
+
+static char tmp[PATH_MAX], *cgrp2dir = NULL;
+static int cgrp2fd = -1;
+static int drm_fd = -1;
+
+/* Figure out where (if) cgroups-v2 is mounted on this machine. */
+static void
+find_cgroup2(void)
+{
+	FILE *f;
+	char *from, *path, *type;
+
+	f = fopen("/proc/mounts", "r");
+	igt_assert(f);
+
+	while (fgets(tmp, sizeof(tmp), f)) {
+		from = strtok(tmp, " ");
+		if (!from) continue;
+
+		path = strtok(NULL, " ");
+		if (!path) continue;
+
+		type = strtok(NULL, " ");
+		if (strcmp(type, "cgroup2") == 0) {
+			cgrp2dir = path;
+			cgrp2fd = open(cgrp2dir, O_DIRECTORY|O_RDONLY);
+			break;
+		}
+	}
+
+	fclose(f);
+
+	igt_skip_on_f(!cgrp2dir, "cgroups-v2 is not mounted\n");
+	igt_skip_on_f(!cgrp2fd, "Insufficient fs permissions on cgroup2 dir\n");
+}
+
+static char tmp_cgroup[PATH_MAX];
+
+static int
+create_tmp_cgroup(void)
+{
+	char *dirname;
+	int fd;
+
+	snprintf(tmp_cgroup, sizeof(tmp_cgroup), "%s/igt_cgroup_XXXXXX",
+		 cgrp2dir);
+	dirname = mkdtemp(tmp_cgroup);
+	igt_assert(dirname);
+
+	fd = open(dirname, O_DIRECTORY|O_RDONLY);
+	igt_assert(fd >= 0);
+
+	return fd;
+}
+
+static void
+rm_tmp_cgroup(int fd)
+{
+	close(fd);
+	rmdir(tmp_cgroup);
+}
+
+static int
+set_prio(int fd, int prio)
+{
+	struct INTERNAL_drm_i915_cgroup_param req;
+
+	req.cgroup_fd = fd;
+	req.flags = 0;
+	req.param = I915_CGROUP_PARAM_PRIORITY_OFFSET;
+	req.value = prio;
+
+	return drmIoctl(drm_fd, INTERNAL_IOCTL_I915_CGROUP_SETPARAM, &req);
+}
+
+igt_main
+{
+	char other_file[PATH_MAX];
+	int ret, fd;
+
+	igt_fixture {
+		find_cgroup2();
+		drm_fd = drm_open_driver_master(DRIVER_INTEL);
+	}
+
+	/* Standard request to set priority.  Should succeed */
+	igt_subtest_f("set-prio") {
+		fd = create_tmp_cgroup();
+		ret = set_prio(fd, 123);
+		igt_fail_on(ret);
+		rm_tmp_cgroup(fd);
+	}
+
+	/* Use an invalid parameter ID.  Should fail. */
+	igt_subtest_f("bad-param") {
+		struct INTERNAL_drm_i915_cgroup_param req;
+
+		fd = create_tmp_cgroup();
+		req.cgroup_fd = fd;
+		req.flags = 0;
+		req.param = 0xDEADBEEF;
+		req.value = 123;
+
+		ret = drmIoctl(drm_fd, INTERNAL_IOCTL_I915_CGROUP_SETPARAM, &req);
+		igt_assert(ret < 0 && errno == EINVAL);
+
+		rm_tmp_cgroup(fd);
+	}
+
+	/* Attempt to set prio with insufficient permissions.  Should fail */
+	igt_subtest_f("insufficient-permissions") {
+		igt_skip_on_f(geteuid() == 0,
+			      "Permissions always succeed for root\n");
+
+		fd = create_tmp_cgroup();
+		fchmod(fd, 0);
+		ret = set_prio(fd, 123);
+		igt_assert(ret < 0 && errno == EACCES);
+		rm_tmp_cgroup(fd);
+	}
+
+	/*
+	 * Pass fd for a cgroup control file instead of cgroup directory itself.
+	 * Should fail.
+	 */
+	igt_subtest_f("control-file-fd") {
+		int fd2;
+
+		fd = create_tmp_cgroup();
+		snprintf(other_file, sizeof(other_file),
+			 "%s/cgroup.procs", tmp_cgroup);
+		fd2 = open(other_file, O_RDONLY);
+		igt_assert(fd2 >= 0);
+
+		ret = set_prio(fd2, 123);
+		igt_assert(ret < 0 && errno == EBADF);
+
+		close(fd2);
+		rm_tmp_cgroup(fd);
+	}
+
+	/*
+	 * Pass an fd for a non-cgroup directory.  Should fail.
+	 * Note that we rely on /tmp being available and writable.
+	 */
+	igt_subtest_f("non-cgroup-fd") {
+		char *dirname;
+
+		strcpy(other_file, "/tmp/igt_XXXXXX");
+		dirname = mkdtemp(other_file);
+		igt_assert(dirname);
+
+		fd = open(dirname, O_DIRECTORY|O_RDONLY);
+		igt_assert(fd >= 0);
+
+		ret = set_prio(fd, 123);
+		igt_assert(ret < 0 && errno == EBADF);
+
+		close(fd);
+		rmdir(dirname);
+	}
+
+	/*
+	 * Reload driver after setting priority.  Should pass.
+	 *
+	 * The priority data will be lost across reload, but the goal is to
+	 * make sure we don't panic during driver removal or subsequent
+	 * assignment of a new priority to the existing cgroup.
+	 */
+	igt_subtest_f("cgroup-reload") {
+		fd = create_tmp_cgroup();
+		ret = set_prio(fd, 123);
+		igt_fail_on(ret);
+
+		ret = igt_i915_driver_unload();
+		igt_fail_on(ret);
+		ret = igt_i915_driver_load(NULL);
+		igt_fail_on(ret);
+
+		ret = set_prio(fd, 456);
+		igt_fail_on(ret);
+
+		rm_tmp_cgroup(fd);
+	}
+}