1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) International Business Machines Corp., 2001 4f08c3bdfSopenharmony_ci * Copyright (c) 2008 Vijay Kumar B. <vijaykumar@bravegnu.org> 5f08c3bdfSopenharmony_ci * Copyright (c) Linux Test Project, 2008-2022 6f08c3bdfSopenharmony_ci * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> 7f08c3bdfSopenharmony_ci */ 8f08c3bdfSopenharmony_ci 9f08c3bdfSopenharmony_ci/*\ 10f08c3bdfSopenharmony_ci * [Description] 11f08c3bdfSopenharmony_ci * 12f08c3bdfSopenharmony_ci * Test whether counter overflow is detected and handled correctly. 13f08c3bdfSopenharmony_ci * 14f08c3bdfSopenharmony_ci * It is not possible to directly overflow the counter using the 15f08c3bdfSopenharmony_ci * write() syscall. Overflows occur when the counter is incremented 16f08c3bdfSopenharmony_ci * from kernel space, in an IRQ context, when it is not possible to 17f08c3bdfSopenharmony_ci * block the calling thread of execution. 18f08c3bdfSopenharmony_ci * 19f08c3bdfSopenharmony_ci * The AIO subsystem internally uses eventfd mechanism for 20f08c3bdfSopenharmony_ci * notification of completion of read or write requests. In this test 21f08c3bdfSopenharmony_ci * we trigger a counter overflow, by setting the counter value to the 22f08c3bdfSopenharmony_ci * max possible value initially. When the AIO subsystem notifies 23f08c3bdfSopenharmony_ci * through the eventfd counter, the counter overflows. 24f08c3bdfSopenharmony_ci * 25f08c3bdfSopenharmony_ci * If the counter starts from an initial value of 0, it will 26f08c3bdfSopenharmony_ci * take decades for an overflow to occur. But since we set the initial 27f08c3bdfSopenharmony_ci * value to the max possible counter value, we are able to cause it to 28f08c3bdfSopenharmony_ci * overflow with a single increment. 29f08c3bdfSopenharmony_ci * 30f08c3bdfSopenharmony_ci * When the counter overflows, the following is tested: 31f08c3bdfSopenharmony_ci * 32f08c3bdfSopenharmony_ci * - POLLERR event occurs in poll() for the eventfd 33f08c3bdfSopenharmony_ci * - readfd_set/writefd_set is set in select() for the eventfd 34f08c3bdfSopenharmony_ci * - the counter value is UINT64_MAX 35f08c3bdfSopenharmony_ci */ 36f08c3bdfSopenharmony_ci 37f08c3bdfSopenharmony_ci#include "tst_test.h" 38f08c3bdfSopenharmony_ci 39f08c3bdfSopenharmony_ci#ifdef HAVE_LIBAIO 40f08c3bdfSopenharmony_ci#ifdef HAVE_IO_SET_EVENTFD 41f08c3bdfSopenharmony_ci 42f08c3bdfSopenharmony_ci#include <poll.h> 43f08c3bdfSopenharmony_ci#include <libaio.h> 44f08c3bdfSopenharmony_ci#include <stdlib.h> 45f08c3bdfSopenharmony_ci#include <sys/eventfd.h> 46f08c3bdfSopenharmony_ci 47f08c3bdfSopenharmony_ci#define MAXEVENTS 16 48f08c3bdfSopenharmony_ci#define BUFSIZE 1024 49f08c3bdfSopenharmony_ci 50f08c3bdfSopenharmony_cistatic int fd; 51f08c3bdfSopenharmony_cistatic int evfd; 52f08c3bdfSopenharmony_cistatic io_context_t ctx; 53f08c3bdfSopenharmony_ci 54f08c3bdfSopenharmony_cistatic void async_write(void) 55f08c3bdfSopenharmony_ci{ 56f08c3bdfSopenharmony_ci struct iocb iocb; 57f08c3bdfSopenharmony_ci struct iocb *iocbap[1]; 58f08c3bdfSopenharmony_ci struct io_event ioev; 59f08c3bdfSopenharmony_ci static char buf[BUFSIZE]; 60f08c3bdfSopenharmony_ci 61f08c3bdfSopenharmony_ci memset(buf, 1, BUFSIZE); 62f08c3bdfSopenharmony_ci 63f08c3bdfSopenharmony_ci io_prep_pwrite(&iocb, fd, buf, sizeof(buf), 0); 64f08c3bdfSopenharmony_ci io_set_eventfd(&iocb, evfd); 65f08c3bdfSopenharmony_ci 66f08c3bdfSopenharmony_ci iocbap[0] = &iocb; 67f08c3bdfSopenharmony_ci TEST(io_submit(ctx, 1, iocbap)); 68f08c3bdfSopenharmony_ci if (TST_RET < 0) 69f08c3bdfSopenharmony_ci tst_brk(TBROK, "io_submit() failed: %s", tst_strerrno(-TST_RET)); 70f08c3bdfSopenharmony_ci 71f08c3bdfSopenharmony_ci TEST(io_getevents(ctx, 1, 1, &ioev, NULL)); 72f08c3bdfSopenharmony_ci if (TST_RET < 0) 73f08c3bdfSopenharmony_ci tst_brk(TBROK, "io_getevents() failed: %s", tst_strerrno(-TST_RET)); 74f08c3bdfSopenharmony_ci} 75f08c3bdfSopenharmony_ci 76f08c3bdfSopenharmony_cistatic void clear_counter(void) 77f08c3bdfSopenharmony_ci{ 78f08c3bdfSopenharmony_ci uint64_t val; 79f08c3bdfSopenharmony_ci uint64_t max = UINT64_MAX - 1; 80f08c3bdfSopenharmony_ci 81f08c3bdfSopenharmony_ci TEST(read(evfd, &val, sizeof(val))); 82f08c3bdfSopenharmony_ci if (TST_RET == -1 && TST_ERR != EAGAIN) 83f08c3bdfSopenharmony_ci tst_brk(TBROK | TERRNO, "read"); 84f08c3bdfSopenharmony_ci 85f08c3bdfSopenharmony_ci SAFE_WRITE(0, evfd, &max, sizeof(max)); 86f08c3bdfSopenharmony_ci} 87f08c3bdfSopenharmony_ci 88f08c3bdfSopenharmony_cistatic void test_select(void) 89f08c3bdfSopenharmony_ci{ 90f08c3bdfSopenharmony_ci fd_set readfds; 91f08c3bdfSopenharmony_ci uint64_t count; 92f08c3bdfSopenharmony_ci struct timeval timeout = { 10, 0 }; 93f08c3bdfSopenharmony_ci 94f08c3bdfSopenharmony_ci clear_counter(); 95f08c3bdfSopenharmony_ci async_write(); 96f08c3bdfSopenharmony_ci 97f08c3bdfSopenharmony_ci FD_ZERO(&readfds); 98f08c3bdfSopenharmony_ci FD_SET(fd, &readfds); 99f08c3bdfSopenharmony_ci 100f08c3bdfSopenharmony_ci tst_res(TINFO, "Checking if select() detects counter overflow"); 101f08c3bdfSopenharmony_ci 102f08c3bdfSopenharmony_ci TEST(select(fd + 1, NULL, &readfds, NULL, &timeout)); 103f08c3bdfSopenharmony_ci if (TST_RET == -1) 104f08c3bdfSopenharmony_ci tst_brk(TBROK | TERRNO, "select"); 105f08c3bdfSopenharmony_ci 106f08c3bdfSopenharmony_ci TST_EXP_EQ_LI(FD_ISSET(fd, &readfds), 1); 107f08c3bdfSopenharmony_ci 108f08c3bdfSopenharmony_ci SAFE_READ(0, evfd, &count, sizeof(count)); 109f08c3bdfSopenharmony_ci TST_EXP_EQ_LI(count, UINT64_MAX); 110f08c3bdfSopenharmony_ci} 111f08c3bdfSopenharmony_ci 112f08c3bdfSopenharmony_cistatic void test_poll(void) 113f08c3bdfSopenharmony_ci{ 114f08c3bdfSopenharmony_ci uint64_t count; 115f08c3bdfSopenharmony_ci struct pollfd pollfd; 116f08c3bdfSopenharmony_ci 117f08c3bdfSopenharmony_ci clear_counter(); 118f08c3bdfSopenharmony_ci async_write(); 119f08c3bdfSopenharmony_ci 120f08c3bdfSopenharmony_ci pollfd.fd = evfd; 121f08c3bdfSopenharmony_ci pollfd.events = POLLIN; 122f08c3bdfSopenharmony_ci pollfd.revents = 0; 123f08c3bdfSopenharmony_ci 124f08c3bdfSopenharmony_ci tst_res(TINFO, "Checking if poll() detects counter overflow"); 125f08c3bdfSopenharmony_ci 126f08c3bdfSopenharmony_ci TEST(poll(&pollfd, 1, 10000)); 127f08c3bdfSopenharmony_ci if (TST_RET == -1) 128f08c3bdfSopenharmony_ci tst_brk(TBROK | TERRNO, "poll"); 129f08c3bdfSopenharmony_ci 130f08c3bdfSopenharmony_ci TST_EXP_EQ_LI(pollfd.revents & POLLERR, POLLERR); 131f08c3bdfSopenharmony_ci 132f08c3bdfSopenharmony_ci SAFE_READ(0, evfd, &count, sizeof(count)); 133f08c3bdfSopenharmony_ci TST_EXP_EQ_LI(count, UINT64_MAX); 134f08c3bdfSopenharmony_ci} 135f08c3bdfSopenharmony_ci 136f08c3bdfSopenharmony_cistatic void setup(void) 137f08c3bdfSopenharmony_ci{ 138f08c3bdfSopenharmony_ci TEST(io_setup(MAXEVENTS, &ctx)); 139f08c3bdfSopenharmony_ci if (TST_RET < 0) 140f08c3bdfSopenharmony_ci tst_brk(TBROK, "io_setup() failed: %s", tst_strerrno(-TST_RET)); 141f08c3bdfSopenharmony_ci 142f08c3bdfSopenharmony_ci fd = SAFE_OPEN("testfile", O_RDWR | O_CREAT, 0644); 143f08c3bdfSopenharmony_ci evfd = TST_EXP_FD(eventfd(0, EFD_NONBLOCK)); 144f08c3bdfSopenharmony_ci} 145f08c3bdfSopenharmony_ci 146f08c3bdfSopenharmony_cistatic void cleanup(void) 147f08c3bdfSopenharmony_ci{ 148f08c3bdfSopenharmony_ci SAFE_CLOSE(evfd); 149f08c3bdfSopenharmony_ci io_destroy(ctx); 150f08c3bdfSopenharmony_ci} 151f08c3bdfSopenharmony_ci 152f08c3bdfSopenharmony_cistatic void run(void) 153f08c3bdfSopenharmony_ci{ 154f08c3bdfSopenharmony_ci test_select(); 155f08c3bdfSopenharmony_ci test_poll(); 156f08c3bdfSopenharmony_ci} 157f08c3bdfSopenharmony_ci 158f08c3bdfSopenharmony_cistatic struct tst_test test = { 159f08c3bdfSopenharmony_ci .test_all = run, 160f08c3bdfSopenharmony_ci .setup = setup, 161f08c3bdfSopenharmony_ci .cleanup = cleanup, 162f08c3bdfSopenharmony_ci .needs_tmpdir = 1, 163f08c3bdfSopenharmony_ci .needs_kconfigs = (const char *[]) { 164f08c3bdfSopenharmony_ci "CONFIG_EVENTFD", 165f08c3bdfSopenharmony_ci NULL 166f08c3bdfSopenharmony_ci }, 167f08c3bdfSopenharmony_ci}; 168f08c3bdfSopenharmony_ci 169f08c3bdfSopenharmony_ci#else /* HAVE_IO_SET_EVENTFD */ 170f08c3bdfSopenharmony_ciTST_TEST_TCONF("eventfd support is not available in AIO subsystem"); 171f08c3bdfSopenharmony_ci#endif 172f08c3bdfSopenharmony_ci#else /* HAVE_LIBAIO */ 173f08c3bdfSopenharmony_ciTST_TEST_TCONF("libaio is not available"); 174f08c3bdfSopenharmony_ci#endif 175