[Intel-gfx] [PATCH igt v2] igt/pm_rpm: Use libc 'ftw' rather than opencoding our own filetree walk

Chris Wilson chris at chris-wilson.co.uk
Wed Aug 23 16:06:42 UTC 2017


By using ftw, we avoid the issue of having to handle directory recursion
ourselves and can focus on the test of checking the reading a
sysfs/debugfs does not break runtime suspend. In the process, disregard
errors when opening the individual files as they may fail for other
reasons.

v2: Bracket the file open/close with the wait_for_suspended() tests.
Whilst the fd is open, it may be keeping the device awake, e.g.
i915_forcewake_user.

Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
 lib/igt_debugfs.c | 50 +++++++++++++++++++++---------
 lib/igt_debugfs.h |  1 +
 lib/igt_sysfs.c   | 41 +++++++++++++++++++------
 lib/igt_sysfs.h   |  1 +
 tests/pm_rpm.c    | 91 ++++++++++++++++++++++++-------------------------------
 5 files changed, 108 insertions(+), 76 deletions(-)

diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c
index ee1f0f54..84066ab8 100644
--- a/lib/igt_debugfs.c
+++ b/lib/igt_debugfs.c
@@ -127,38 +127,38 @@ const char *igt_debugfs_mount(void)
 }
 
 /**
- * igt_debugfs_dir:
+ * igt_debugfs_path:
  * @device: fd of the device
+ * @path: buffer to store path
+ * @pathlen: len of @path buffer.
  *
- * This opens the debugfs directory corresponding to device for use
- * with igt_sysfs_get() and related functions.
+ * This finds the debugfs directory corresponding to @device.
  *
  * Returns:
- * The directory fd, or -1 on failure.
+ * The directory path, or NULL on failure.
  */
-int igt_debugfs_dir(int device)
+char *igt_debugfs_path(int device, char *path, int pathlen)
 {
 	struct stat st;
 	const char *debugfs_root;
-	char path[200];
 	int idx;
 
 	if (fstat(device, &st)) {
 		igt_debug("Couldn't stat FD for DRM device: %s\n", strerror(errno));
-		return -1;
+		return NULL;
 	}
 
 	if (!S_ISCHR(st.st_mode)) {
 		igt_debug("FD for DRM device not a char device!\n");
-		return -1;
+		return NULL;
 	}
 
 	debugfs_root = igt_debugfs_mount();
 
 	idx = minor(st.st_rdev);
-	snprintf(path, sizeof(path), "%s/dri/%d/name", debugfs_root, idx);
+	snprintf(path, pathlen, "%s/dri/%d/name", debugfs_root, idx);
 	if (stat(path, &st))
-		return -1;
+		return NULL;
 
 	if (idx >= 64) {
 		int file, name_len, cmp_len;
@@ -166,17 +166,17 @@ int igt_debugfs_dir(int device)
 
 		file = open(path, O_RDONLY);
 		if (file < 0)
-			return -1;
+			return NULL;
 
 		name_len = read(file, name, sizeof(name));
 		close(file);
 
 		for (idx = 0; idx < 16; idx++) {
-			snprintf(path, sizeof(path), "%s/dri/%d/name",
+			snprintf(path, pathlen, "%s/dri/%d/name",
 				 debugfs_root, idx);
 			file = open(path, O_RDONLY);
 			if (file < 0)
-				return -1;
+				return NULL;
 
 			cmp_len = read(file, cmp, sizeof(cmp));
 			close(file);
@@ -186,10 +186,30 @@ int igt_debugfs_dir(int device)
 		}
 
 		if (idx == 16)
-			return -1;
+			return NULL;
 	}
 
-	snprintf(path, sizeof(path), "%s/dri/%d", debugfs_root, idx);
+	snprintf(path, pathlen, "%s/dri/%d", debugfs_root, idx);
+	return path;
+}
+
+/**
+ * igt_debugfs_dir:
+ * @device: fd of the device
+ *
+ * This opens the debugfs directory corresponding to device for use
+ * with igt_sysfs_get() and related functions.
+ *
+ * Returns:
+ * The directory fd, or -1 on failure.
+ */
+int igt_debugfs_dir(int device)
+{
+	char path[200];
+
+	if (!igt_debugfs_path(device, path, sizeof(path)))
+		return -1;
+
 	igt_debug("Opening debugfs directory '%s'\n", path);
 	return open(path, O_RDONLY);
 }
diff --git a/lib/igt_debugfs.h b/lib/igt_debugfs.h
index f1a76406..4fa49d21 100644
--- a/lib/igt_debugfs.h
+++ b/lib/igt_debugfs.h
@@ -32,6 +32,7 @@
 enum pipe;
 
 const char *igt_debugfs_mount(void);
+char *igt_debugfs_path(int device, char *path, int pathlen);
 
 int igt_debugfs_dir(int device);
 
diff --git a/lib/igt_sysfs.c b/lib/igt_sysfs.c
index 15ed34be..d412610d 100644
--- a/lib/igt_sysfs.c
+++ b/lib/igt_sysfs.c
@@ -86,26 +86,26 @@ static int writeN(int fd, const char *buf, int len)
 }
 
 /**
- * igt_sysfs_open:
+ * igt_sysfs_path:
  * @device: fd of the device (or -1 to default to Intel)
+ * @path: buffer to fill with the sysfs path to the device
+ * @pathlen: length of @path buffer
  * @idx: optional pointer to store the card index of the opened device
  *
- * This opens the sysfs directory corresponding to device for use
- * with igt_sysfs_set() and igt_sysfs_get().
+ * This finds the sysfs directory corresponding to @device.
  *
  * Returns:
- * The directory fd, or -1 on failure.
+ * The directory path, or NULL on failure.
  */
-int igt_sysfs_open(int device, int *idx)
+char *igt_sysfs_path(int device, char *path, int pathlen, int *idx)
 {
-	char path[80];
 	struct stat st;
 
 	if (device != -1 && (fstat(device, &st) || !S_ISCHR(st.st_mode)))
-		return -1;
+		return NULL;
 
 	for (int n = 0; n < 16; n++) {
-		int len = sprintf(path, "/sys/class/drm/card%d", n);
+		int len = snprintf(path, pathlen, "/sys/class/drm/card%d", n);
 		if (device != -1) {
 			FILE *file;
 			int ret, maj, min;
@@ -132,10 +132,31 @@ int igt_sysfs_open(int device, int *idx)
 		path[len] = '\0';
 		if (idx)
 			*idx = n;
-		return open(path, O_RDONLY);
+		return path;
 	}
 
-	return -1;
+	return NULL;
+}
+
+/**
+ * igt_sysfs_open:
+ * @device: fd of the device (or -1 to default to Intel)
+ * @idx: optional pointer to store the card index of the opened device
+ *
+ * This opens the sysfs directory corresponding to device for use
+ * with igt_sysfs_set() and igt_sysfs_get().
+ *
+ * Returns:
+ * The directory fd, or -1 on failure.
+ */
+int igt_sysfs_open(int device, int *idx)
+{
+	char path[80];
+
+	if (!igt_sysfs_path(device, path, sizeof(path), idx))
+		return -1;
+
+	return open(path, O_RDONLY);
 }
 
 /**
diff --git a/lib/igt_sysfs.h b/lib/igt_sysfs.h
index d666438a..3ee89b0f 100644
--- a/lib/igt_sysfs.h
+++ b/lib/igt_sysfs.h
@@ -27,6 +27,7 @@
 
 #include <stdbool.h>
 
+char *igt_sysfs_path(int device, char *path, int pathlen, int *idx);
 int igt_sysfs_open(int device, int *idx);
 int igt_sysfs_open_parameters(int device);
 bool igt_sysfs_set_parameter(int device,
diff --git a/tests/pm_rpm.c b/tests/pm_rpm.c
index 47c9f114..20e8ca72 100644
--- a/tests/pm_rpm.c
+++ b/tests/pm_rpm.c
@@ -25,13 +25,13 @@
  *
  */
 
-#include "igt.h"
-#include "igt_kmod.h"
-#include "igt_sysfs.h"
+#include "config.h"
+
 #include <stdio.h>
 #include <stdint.h>
 #include <stdbool.h>
 #include <string.h>
+#include <ftw.h>
 
 #include <unistd.h>
 #include <fcntl.h>
@@ -45,6 +45,10 @@
 
 #include <drm.h>
 
+#include "igt.h"
+#include "igt_kmod.h"
+#include "igt_sysfs.h"
+#include "igt_debugfs.h"
 
 #define MSR_PC8_RES	0x630
 #define MSR_PC9_RES	0x631
@@ -830,55 +834,40 @@ static void i2c_subtest(void)
 	enable_one_screen(&ms_data);
 }
 
-static void read_full_file(int fd, const char *name)
-{
-	int rc;
-	char buf[128];
-
-	igt_assert_f(wait_for_suspended(), "File: %s\n", name);
-
-	do {
-		rc = read(fd, buf, ARRAY_SIZE(buf));
-	} while (rc == ARRAY_SIZE(buf));
-
-	igt_assert_f(wait_for_suspended(), "File: %s\n", name);
-}
-
-static void read_files_from_dir(int path, int level)
+static int read_entry(const char *filepath,
+		      const struct stat *info,
+		      const int typeflag,
+		      struct FTW *pathinfo)
 {
-	DIR *dir;
-	struct dirent *dirent;
+	char buf[4096];
+	int fd;
 	int rc;
 
-	dir = fdopendir(path);
-	igt_assert(dir);
-
-	igt_assert_lt(level, 128);
-
-	while ((dirent = readdir(dir))) {
-		struct stat stat_buf;
-		int de;
+	igt_assert_f(wait_for_suspended(), "Before opening: %s (%s)\n",
+		     filepath + pathinfo->base, filepath);
 
-		if (strcmp(dirent->d_name, ".") == 0)
-			continue;
-		if (strcmp(dirent->d_name, "..") == 0)
-			continue;
-
-		de = openat(path, dirent->d_name, O_RDONLY);
+	fd = open(filepath, O_RDONLY | O_NONBLOCK);
+	if (fd < 0) {
+		igt_debug("Failed to open '%s': %m\n", filepath);
+		return 0;
+	}
 
-		rc = fstat(de, &stat_buf);
-		igt_assert_eq(rc, 0);
+	do {
+		rc = read(fd, buf, sizeof(buf));
+	} while (rc == sizeof(buf));
 
-		if (S_ISDIR(stat_buf.st_mode))
-			read_files_from_dir(de, level + 1);
+	close(fd);
 
-		if (S_ISREG(stat_buf.st_mode))
-			read_full_file(de, dirent->d_name);
+	igt_assert_f(wait_for_suspended(), "After closing: %s (%s)\n",
+		     filepath + pathinfo->base, filepath);
 
-		close(de);
-	}
+	return 0;
+}
 
-	closedir(dir);
+static void walk_fs(char *path)
+{
+	disable_all_screens_and_wait(&ms_data);
+	nftw(path, read_entry, 20, FTW_PHYS | FTW_MOUNT);
 }
 
 /* This test will probably pass, with a small chance of hanging the machine in
@@ -886,21 +875,21 @@ static void read_files_from_dir(int path, int level)
  * errors, so a "pass" here should be confirmed by a check on dmesg. */
 static void debugfs_read_subtest(void)
 {
-	disable_all_screens_and_wait(&ms_data);
+	char path[256];
 
-	read_files_from_dir(debugfs, 0);
+	igt_require_f(igt_debugfs_path(drm_fd, path, sizeof(path)),
+		      "Can't find the debugfs directory\n");
+	walk_fs(path);
 }
 
 /* Read the comment on debugfs_read_subtest(). */
 static void sysfs_read_subtest(void)
 {
-	int dir = igt_sysfs_open(drm_fd, NULL);
-	igt_require_f(dir != -1, "Can't open the sysfs directory\n");
-
-	disable_all_screens_and_wait(&ms_data);
+	char path[80];
 
-	read_files_from_dir(dir, 0);
-	close(dir);
+	igt_require_f(igt_sysfs_path(drm_fd, path, sizeof(path), NULL),
+		      "Can't find the sysfs directory\n");
+	walk_fs(path);
 }
 
 /* Make sure we don't suspend when we have the i915_forcewake_user file open. */
-- 
2.14.1



More information about the Intel-gfx mailing list