1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) Linux Test Project, 2021
4f08c3bdfSopenharmony_ci * Author: Xie Ziyao <ziyaoxie@outlook.com>
5f08c3bdfSopenharmony_ci */
6f08c3bdfSopenharmony_ci
7f08c3bdfSopenharmony_ci/*\
8f08c3bdfSopenharmony_ci * [Description]
9f08c3bdfSopenharmony_ci *
10f08c3bdfSopenharmony_ci * Verify that epoll_ctl() fails with ELOOP if fd refers to an epoll instance
11f08c3bdfSopenharmony_ci * and this EPOLL_CTL_ADD operation would result in a circular loop of epoll
12f08c3bdfSopenharmony_ci * instances monitoring one another.
13f08c3bdfSopenharmony_ci */
14f08c3bdfSopenharmony_ci
15f08c3bdfSopenharmony_ci#include <poll.h>
16f08c3bdfSopenharmony_ci#include <sys/epoll.h>
17f08c3bdfSopenharmony_ci
18f08c3bdfSopenharmony_ci#include "tst_test.h"
19f08c3bdfSopenharmony_ci
20f08c3bdfSopenharmony_ci#define MAX_DEPTH 5
21f08c3bdfSopenharmony_ci
22f08c3bdfSopenharmony_cistatic int epfd, origin_epfd, new_epfd;
23f08c3bdfSopenharmony_cistatic int fd[2];
24f08c3bdfSopenharmony_ci
25f08c3bdfSopenharmony_cistatic struct epoll_event events = {.events = EPOLLIN};
26f08c3bdfSopenharmony_ci
27f08c3bdfSopenharmony_cistatic void setup(void)
28f08c3bdfSopenharmony_ci{
29f08c3bdfSopenharmony_ci	int i;
30f08c3bdfSopenharmony_ci
31f08c3bdfSopenharmony_ci	SAFE_PIPE(fd);
32f08c3bdfSopenharmony_ci
33f08c3bdfSopenharmony_ci	for (i = 0, epfd = fd[0]; i < MAX_DEPTH; i++, epfd = new_epfd) {
34f08c3bdfSopenharmony_ci		new_epfd = epoll_create(1);
35f08c3bdfSopenharmony_ci		if (new_epfd == -1)
36f08c3bdfSopenharmony_ci			tst_brk(TBROK | TERRNO, "fail to create epoll instance");
37f08c3bdfSopenharmony_ci
38f08c3bdfSopenharmony_ci		if (i == 0)
39f08c3bdfSopenharmony_ci			origin_epfd = new_epfd;
40f08c3bdfSopenharmony_ci
41f08c3bdfSopenharmony_ci		events.data.fd = epfd;
42f08c3bdfSopenharmony_ci		if (epoll_ctl(new_epfd, EPOLL_CTL_ADD, epfd, &events))
43f08c3bdfSopenharmony_ci			tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)");
44f08c3bdfSopenharmony_ci	}
45f08c3bdfSopenharmony_ci
46f08c3bdfSopenharmony_ci	events.data.fd = fd[0];
47f08c3bdfSopenharmony_ci	if (epoll_ctl(origin_epfd, EPOLL_CTL_DEL, fd[0], &events))
48f08c3bdfSopenharmony_ci		tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_DEL, ...)");
49f08c3bdfSopenharmony_ci}
50f08c3bdfSopenharmony_ci
51f08c3bdfSopenharmony_cistatic void cleanup(void)
52f08c3bdfSopenharmony_ci{
53f08c3bdfSopenharmony_ci	if (fd[0])
54f08c3bdfSopenharmony_ci		SAFE_CLOSE(fd[0]);
55f08c3bdfSopenharmony_ci
56f08c3bdfSopenharmony_ci	if (fd[1])
57f08c3bdfSopenharmony_ci		SAFE_CLOSE(fd[1]);
58f08c3bdfSopenharmony_ci}
59f08c3bdfSopenharmony_ci
60f08c3bdfSopenharmony_cistatic void verify_epoll_ctl(void)
61f08c3bdfSopenharmony_ci{
62f08c3bdfSopenharmony_ci	events.data.fd = epfd;
63f08c3bdfSopenharmony_ci	TST_EXP_FAIL(epoll_ctl(origin_epfd, EPOLL_CTL_ADD, epfd, &events),
64f08c3bdfSopenharmony_ci		     ELOOP, "epoll_ctl(..., EPOLL_CTL_ADD, ...)");
65f08c3bdfSopenharmony_ci}
66f08c3bdfSopenharmony_ci
67f08c3bdfSopenharmony_cistatic struct tst_test test = {
68f08c3bdfSopenharmony_ci	.setup = setup,
69f08c3bdfSopenharmony_ci	.cleanup = cleanup,
70f08c3bdfSopenharmony_ci	.test_all = verify_epoll_ctl,
71f08c3bdfSopenharmony_ci};
72