tools/testing/selftests/iommu/iommufd_fail_nth.c

Source file repositories/reference/linux-study-clean/tools/testing/selftests/iommu/iommufd_fail_nth.c

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/iommu/iommufd_fail_nth.c
Extension
.c
Size
19333 bytes
Lines
749
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: implementation source
Status
source implementation candidate

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

struct fail_nth_state {
	int proc_fd;
	unsigned int iteration;
};

static void fail_nth_first(struct __test_metadata *_metadata,
			   struct fail_nth_state *nth_state)
{
	char buf[300];

	snprintf(buf, sizeof(buf), "/proc/self/task/%u/fail-nth", getpid());
	nth_state->proc_fd = open(buf, O_RDWR);
	ASSERT_NE(-1, nth_state->proc_fd);
}

static bool fail_nth_next(struct __test_metadata *_metadata,
			  struct fail_nth_state *nth_state,
			  int test_result)
{
	static const char disable_nth[] = "0";
	char buf[300];

	/*
	 * This is just an arbitrary limit based on the current kernel
	 * situation. Changes in the kernel can dramatically change the number of
	 * required fault injection sites, so if this hits it doesn't
	 * necessarily mean a test failure, just that the limit has to be made
	 * bigger.
	 */
	ASSERT_GT(1000, nth_state->iteration);
	if (nth_state->iteration != 0) {
		ssize_t res;
		ssize_t res2;

		buf[0] = 0;
		/*
		 * Annoyingly disabling the nth can also fail. This means
		 * the test passed without triggering failure
		 */
		res = pread(nth_state->proc_fd, buf, sizeof(buf), 0);
		if (res == -1 && errno == EFAULT) {
			buf[0] = '1';
			buf[1] = '\n';
			res = 2;
		}

		res2 = pwrite(nth_state->proc_fd, disable_nth,
			      ARRAY_SIZE(disable_nth) - 1, 0);
		if (res2 == -1 && errno == EFAULT) {
			res2 = pwrite(nth_state->proc_fd, disable_nth,
				      ARRAY_SIZE(disable_nth) - 1, 0);
			buf[0] = '1';
			buf[1] = '\n';
		}
		ASSERT_EQ(ARRAY_SIZE(disable_nth) - 1, res2);

		/* printf("  nth %u result=%d nth=%u\n", nth_state->iteration,
		       test_result, atoi(buf)); */
		fflush(stdout);
		ASSERT_LT(1, res);
		if (res != 2 || buf[0] != '0' || buf[1] != '\n')
			return false;
	} else {
		/* printf("  nth %u result=%d\n", nth_state->iteration,
		       test_result); */
	}
	nth_state->iteration++;
	return true;
}

/*
 * This is called during the test to start failure injection. It allows the test
 * to do some setup that has already been swept and thus reduce the required
 * iterations.
 */
void __fail_nth_enable(struct __test_metadata *_metadata,
		       struct fail_nth_state *nth_state)
{
	char buf[300];
	size_t len;

	if (!nth_state->iteration)
		return;

	len = snprintf(buf, sizeof(buf), "%u", nth_state->iteration);
	ASSERT_EQ(len, pwrite(nth_state->proc_fd, buf, len, 0));
}
#define fail_nth_enable() __fail_nth_enable(_metadata, _nth_state)

#define TEST_FAIL_NTH(fixture_name, name)                                           \

Annotation

Implementation Notes