* [LTP] [PATCH 1/3] openposix/aio_cancel: Add helper functions for setup and cleanup
2026-02-03 12:50 [LTP] [PATCH 0/3] Rewrite aio_cancel_2-1 Martin Doucha
@ 2026-02-03 12:50 ` Martin Doucha
2026-02-11 12:49 ` Andrea Cervesato via ltp
2026-02-11 12:59 ` Cyril Hrubis
2026-02-03 12:50 ` [LTP] [PATCH 2/3] openposix/aio_cancel: Use setup helper functions in tests 5 and 7 Martin Doucha
` (2 subsequent siblings)
3 siblings, 2 replies; 12+ messages in thread
From: Martin Doucha @ 2026-02-03 12:50 UTC (permalink / raw)
To: ltp
Add helper functions for setting up and cleaning up boilerplate
aio requests to a socket pair. The socket pair approach is useful
for tests which need some requests to block in order to prevent
race conditions.
Signed-off-by: Martin Doucha <mdoucha@suse.cz>
---
.../open_posix_testsuite/include/aio_test.h | 94 +++++++++++++++++++
1 file changed, 94 insertions(+)
create mode 100644 testcases/open_posix_testsuite/include/aio_test.h
diff --git a/testcases/open_posix_testsuite/include/aio_test.h b/testcases/open_posix_testsuite/include/aio_test.h
new file mode 100644
index 000000000..9de0a4d93
--- /dev/null
+++ b/testcases/open_posix_testsuite/include/aio_test.h
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2024 SUSE LLC <mdoucha@suse.cz>
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <aio.h>
+#include <sys/socket.h>
+
+static int setup_aio(const char *testname, int fd_pair[2], struct aiocb *reqs,
+ unsigned int count)
+{
+ unsigned int i;
+ int ret;
+ int bufsize;
+ socklen_t argsize = sizeof(bufsize);
+
+ /* Open anonymous sockets */
+ ret = socketpair(AF_UNIX, SOCK_DGRAM, 0, fd_pair);
+
+ if (ret) {
+ printf("%s Error creating sockets(): %s\n", testname,
+ strerror(errno));
+ return -1;
+ }
+
+ ret = getsockopt(fd_pair[0], SOL_SOCKET, SO_SNDBUF, &bufsize, &argsize);
+ if (ret) {
+ printf("%s Error reading socket buffer size: %s\n", testname,
+ strerror(errno));
+ close(fd_pair[0]);
+ close(fd_pair[1]);
+ return -1;
+ }
+
+ /* Socket buffer size is twice the maximum message size */
+ bufsize /= 2;
+ memset(reqs, 0, sizeof(struct aiocb) * count);
+
+ /* Setup basic AIO requests */
+ for (i = 0; i < count; i++) {
+ reqs[i].aio_fildes = fd_pair[0];
+ reqs[i].aio_buf = malloc(bufsize);
+
+ if (!reqs[i].aio_buf) {
+ ret = errno;
+ break;
+ }
+
+ reqs[i].aio_nbytes = bufsize;
+ reqs[i].aio_sigevent.sigev_notify = SIGEV_NONE;
+ memset((void *)reqs[i].aio_buf, 0xaa, bufsize);
+ }
+
+ /* Setup successful */
+ if (i >= count)
+ return 0;
+
+ /* malloc() failed above */
+ for (i = 0; i < count; i++)
+ free((void *)reqs[i].aio_buf);
+
+ printf("%s malloc() failed: %s\n", testname, strerror(ret));
+ close(fd_pair[0]);
+ close(fd_pair[1]);
+ return -1;
+}
+
+static void cleanup_aio(int fd_pair[2], struct aiocb *reqs, unsigned int count)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < count; i++) {
+ if (!reqs[i].aio_buf)
+ break;
+
+ ret = aio_error(reqs + i);
+
+ /* flush written data from the socket */
+ if (ret == 0 || ret == EINPROGRESS) {
+ read(fd_pair[1], (void *)reqs[i].aio_buf,
+ reqs[i].aio_nbytes);
+ }
+
+ free((void *)reqs[i].aio_buf);
+ }
+
+ close(fd_pair[0]);
+ close(fd_pair[1]);
+}
--
2.52.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 12+ messages in thread* [LTP] [PATCH 2/3] openposix/aio_cancel: Use setup helper functions in tests 5 and 7
2026-02-03 12:50 [LTP] [PATCH 0/3] Rewrite aio_cancel_2-1 Martin Doucha
2026-02-03 12:50 ` [LTP] [PATCH 1/3] openposix/aio_cancel: Add helper functions for setup and cleanup Martin Doucha
@ 2026-02-03 12:50 ` Martin Doucha
2026-02-11 12:48 ` Andrea Cervesato via ltp
2026-02-11 13:01 ` Cyril Hrubis
2026-02-03 12:50 ` [LTP] [PATCH 3/3] aio_cancel_2-1: Rewrite test Martin Doucha
2026-02-11 13:01 ` [LTP] [PATCH 0/3] Rewrite aio_cancel_2-1 Andrea Cervesato via ltp
3 siblings, 2 replies; 12+ messages in thread
From: Martin Doucha @ 2026-02-03 12:50 UTC (permalink / raw)
To: ltp
Simplify setup and cleanup in recently rewritten tests.
Signed-off-by: Martin Doucha <mdoucha@suse.cz>
---
.../conformance/interfaces/aio_cancel/5-1.c | 79 +++----------------
.../conformance/interfaces/aio_cancel/7-1.c | 79 +++----------------
2 files changed, 23 insertions(+), 135 deletions(-)
diff --git a/testcases/open_posix_testsuite/conformance/interfaces/aio_cancel/5-1.c b/testcases/open_posix_testsuite/conformance/interfaces/aio_cancel/5-1.c
index 559625b13..e7dfca124 100644
--- a/testcases/open_posix_testsuite/conformance/interfaces/aio_cancel/5-1.c
+++ b/testcases/open_posix_testsuite/conformance/interfaces/aio_cancel/5-1.c
@@ -25,18 +25,13 @@
*
*/
-#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
#include <time.h>
-#include <aio.h>
-#include <sys/socket.h>
#include "posixtest.h"
+#include "aio_test.h"
#define TNAME "aio_cancel/5-1.c"
@@ -46,29 +41,6 @@
static int fds[2];
static struct aiocb aiocb[BUF_NB];
-static void cleanup(void)
-{
- int i, ret;
-
- for (i = 0; i < BUF_NB; i++) {
- if (!aiocb[i].aio_buf)
- break;
-
- ret = aio_error(&aiocb[i]);
-
- /* flush written data from the socket */
- if (ret == 0 || ret == EINPROGRESS) {
- read(fds[1], (void *)aiocb[i].aio_buf,
- aiocb[i].aio_nbytes);
- }
-
- free((void *)aiocb[i].aio_buf);
- }
-
- close(fds[0]);
- close(fds[1]);
-}
-
int main(void)
{
char *buf[BUF_NB];
@@ -76,49 +48,24 @@ int main(void)
int ret;
int bufsize;
int exp_ret;
- socklen_t argsize = sizeof(bufsize);
const struct timespec sleep_ts = { .tv_sec = 0, .tv_nsec = 10000000 };
if (sysconf(_SC_ASYNCHRONOUS_IO) < 200112L)
return PTS_UNSUPPORTED;
- ret = socketpair(AF_UNIX, SOCK_DGRAM, 0, fds);
- if (ret == -1) {
- printf(TNAME " Error creating sockets(): %s\n",
- strerror(errno));
+ if (setup_aio(TNAME, fds, aiocb, BUF_NB))
return PTS_UNRESOLVED;
- }
- ret = getsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, &bufsize, &argsize);
- if (ret == -1) {
- printf(TNAME " Error reading socket buffer size: %s\n",
- strerror(errno));
- cleanup();
- return PTS_UNRESOLVED;
- }
+ bufsize = aiocb[0].aio_nbytes;
- /* Socket buffer size is twice the maximum message size */
- bufsize /= 2;
-
- /* create AIO req */
+ /* submit AIO req */
for (i = 0; i < BUF_NB; i++) {
- buf[i] = malloc(bufsize);
- if (buf[i] == NULL) {
- printf(TNAME " Error at malloc(): %s\n",
- strerror(errno));
- cleanup();
- return PTS_UNRESOLVED;
- }
- aiocb[i].aio_fildes = fds[0];
- aiocb[i].aio_buf = buf[i];
- aiocb[i].aio_nbytes = bufsize;
- aiocb[i].aio_offset = 0;
- aiocb[i].aio_sigevent.sigev_notify = SIGEV_NONE;
+ buf[i] = (char *)aiocb[i].aio_buf;
if (aio_write(&aiocb[i]) == -1) {
printf(TNAME " loop %d: Error at aio_write(): %s\n",
i, strerror(errno));
- cleanup();
+ cleanup_aio(fds, aiocb, BUF_NB);
return PTS_FAIL;
}
}
@@ -135,7 +82,7 @@ int main(void)
if (ret) {
printf(TNAME " Task #%d failed to complete: %s\n",
BLOCKED_TASK - 1, strerror(ret == -1 ? errno : ret));
- cleanup();
+ cleanup_aio(fds, aiocb, BUF_NB);
return PTS_FAIL;
}
@@ -143,14 +90,14 @@ int main(void)
ret = aio_cancel(fds[0], NULL);
if (ret == -1) {
printf(TNAME " Error at aio_cancel(): %s\n", strerror(errno));
- cleanup();
+ cleanup_aio(fds, aiocb, BUF_NB);
return PTS_FAIL;
}
if (ret != AIO_NOTCANCELED) {
printf(TNAME " Unexpected aio_cancel() return value: %s\n",
strerror(ret));
- cleanup();
+ cleanup_aio(fds, aiocb, BUF_NB);
return PTS_FAIL;
}
@@ -162,7 +109,7 @@ int main(void)
printf(TNAME " Bad task #%d result: %s "
"(expected EINPROGRESS)\n",
i, strerror(ret));
- cleanup();
+ cleanup_aio(fds, aiocb, BUF_NB);
return PTS_FAIL;
}
@@ -175,7 +122,7 @@ int main(void)
SIGEV_NONE)) {
printf(TNAME " aiocbp modified\n");
- cleanup();
+ cleanup_aio(fds, aiocb, BUF_NB);
return PTS_FAIL;
}
@@ -186,12 +133,12 @@ int main(void)
if (ret != exp_ret) {
printf(TNAME " Bad task #%d result: %s (expected %s)\n",
i, strerror(ret), strerror(exp_ret));
- cleanup();
+ cleanup_aio(fds, aiocb, BUF_NB);
return PTS_FAIL;
}
}
- cleanup();
+ cleanup_aio(fds, aiocb, BUF_NB);
printf("Test PASSED\n");
return PTS_PASS;
}
diff --git a/testcases/open_posix_testsuite/conformance/interfaces/aio_cancel/7-1.c b/testcases/open_posix_testsuite/conformance/interfaces/aio_cancel/7-1.c
index 75cd838a3..9fb584656 100644
--- a/testcases/open_posix_testsuite/conformance/interfaces/aio_cancel/7-1.c
+++ b/testcases/open_posix_testsuite/conformance/interfaces/aio_cancel/7-1.c
@@ -27,16 +27,11 @@
* Otherwise pass.
*/
-#include <stdio.h>
#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
#include <time.h>
-#include <aio.h>
-#include <sys/socket.h>
#include "posixtest.h"
+#include "aio_test.h"
#define TNAME "aio_cancel/7-1.c"
@@ -46,79 +41,25 @@
static int fds[2];
static struct aiocb aiocb[BUF_NB];
-static void cleanup(void)
-{
- int i, ret;
-
- for (i = 0; i < BUF_NB; i++) {
- if (!aiocb[i].aio_buf)
- break;
-
- ret = aio_error(&aiocb[i]);
-
- /* flush written data from the socket */
- if (ret == 0 || ret == EINPROGRESS) {
- read(fds[1], (void *)aiocb[i].aio_buf,
- aiocb[i].aio_nbytes);
- }
-
- free((void *)aiocb[i].aio_buf);
- }
-
- close(fds[0]);
- close(fds[1]);
-}
-
int main(void)
{
int i;
int gret;
- int bufsize;
int exp_ret;
- socklen_t argsize = sizeof(bufsize);
const struct timespec sleep_ts = { .tv_sec = 0, .tv_nsec = 10000000 };
if (sysconf(_SC_ASYNCHRONOUS_IO) < 200112L)
return PTS_UNSUPPORTED;
- gret = socketpair(AF_UNIX, SOCK_DGRAM, 0, fds);
- if (gret == -1) {
- printf(TNAME " Error creating sockets(): %s\n",
- strerror(errno));
+ if (setup_aio(TNAME, fds, aiocb, BUF_NB))
return PTS_UNRESOLVED;
- }
- gret = getsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, &bufsize, &argsize);
- if (gret == -1) {
- printf(TNAME " Error reading socket buffer size: %s\n",
- strerror(errno));
- cleanup();
- return PTS_UNRESOLVED;
- }
-
- /* Socket buffer size is twice the maximum message size */
- bufsize /= 2;
-
- /* create AIO req */
+ /* submit AIO req */
for (i = 0; i < BUF_NB; i++) {
- aiocb[i].aio_fildes = fds[0];
- aiocb[i].aio_buf = malloc(bufsize);
-
- if (aiocb[i].aio_buf == NULL) {
- printf(TNAME " Error at malloc(): %s\n",
- strerror(errno));
- cleanup();
- return PTS_UNRESOLVED;
- }
-
- aiocb[i].aio_nbytes = bufsize;
- aiocb[i].aio_offset = 0;
- aiocb[i].aio_sigevent.sigev_notify = SIGEV_NONE;
-
if (aio_write(&aiocb[i]) == -1) {
printf(TNAME " loop %d: Error at aio_write(): %s\n",
i, strerror(errno));
- cleanup();
+ cleanup_aio(fds, aiocb, BUF_NB);
return PTS_FAIL;
}
}
@@ -135,7 +76,7 @@ int main(void)
if (gret) {
printf(TNAME " Task #%d failed to complete: %s\n",
BLOCKED_TASK - 1, strerror(gret == -1 ? errno : gret));
- cleanup();
+ cleanup_aio(fds, aiocb, BUF_NB);
return PTS_FAIL;
}
@@ -143,14 +84,14 @@ int main(void)
gret = aio_cancel(fds[0], NULL);
if (gret == -1) {
printf(TNAME " Error at aio_cancel(): %s\n", strerror(errno));
- cleanup();
+ cleanup_aio(fds, aiocb, BUF_NB);
return PTS_FAIL;
}
if (gret != AIO_NOTCANCELED) {
printf(TNAME " Unexpected aio_cancel() return value: %s\n",
strerror(gret));
- cleanup();
+ cleanup_aio(fds, aiocb, BUF_NB);
return PTS_FAIL;
}
@@ -172,19 +113,19 @@ int main(void)
printf(TNAME " Bad task #%d result: %s "
"(expected EINPROGRESS)\n",
i, strerror(ret));
- cleanup();
+ cleanup_aio(fds, aiocb, BUF_NB);
return PTS_FAIL;
}
if (ret != exp_ret) {
printf(TNAME " Bad task #%d result: %s (expected %s)\n",
i, strerror(ret), strerror(exp_ret));
- cleanup();
+ cleanup_aio(fds, aiocb, BUF_NB);
return PTS_FAIL;
}
}
- cleanup();
+ cleanup_aio(fds, aiocb, BUF_NB);
printf("Test PASSED\n");
return PTS_PASS;
}
--
2.52.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 12+ messages in thread* [LTP] [PATCH 3/3] aio_cancel_2-1: Rewrite test
2026-02-03 12:50 [LTP] [PATCH 0/3] Rewrite aio_cancel_2-1 Martin Doucha
2026-02-03 12:50 ` [LTP] [PATCH 1/3] openposix/aio_cancel: Add helper functions for setup and cleanup Martin Doucha
2026-02-03 12:50 ` [LTP] [PATCH 2/3] openposix/aio_cancel: Use setup helper functions in tests 5 and 7 Martin Doucha
@ 2026-02-03 12:50 ` Martin Doucha
2026-02-11 14:43 ` Cyril Hrubis
2026-02-11 13:01 ` [LTP] [PATCH 0/3] Rewrite aio_cancel_2-1 Andrea Cervesato via ltp
3 siblings, 1 reply; 12+ messages in thread
From: Martin Doucha @ 2026-02-03 12:50 UTC (permalink / raw)
To: ltp
The test schedules multiple async writes into a file and then hopes that
at least one will block long enough that it can be canceled
before completion. Use a socket pair instead of a file to force async
writes to block indefinitely and make sure at least one can be canceled.
Then cancel all requests on the input socket and check that all writes
after the blocked one have been canceled. This fixes a race condition
where aio_cancel() could be delayed until after all writes have already
completed, making the test unreliable.
Signed-off-by: Martin Doucha <mdoucha@suse.cz>
---
Tested on kernels v4.4 and v6.12.
.../conformance/interfaces/aio_cancel/2-1.c | 86 ++++++++++---------
1 file changed, 46 insertions(+), 40 deletions(-)
diff --git a/testcases/open_posix_testsuite/conformance/interfaces/aio_cancel/2-1.c b/testcases/open_posix_testsuite/conformance/interfaces/aio_cancel/2-1.c
index 63dc6b0ec..6b5a2137b 100644
--- a/testcases/open_posix_testsuite/conformance/interfaces/aio_cancel/2-1.c
+++ b/testcases/open_posix_testsuite/conformance/interfaces/aio_cancel/2-1.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2004, Bull SA. All rights reserved.
+ * Copyright (c) 2025 SUSE LLC
* Created by: Laurent.Vivier@bull.net
* This file is licensed under the GPL license. For the full content
* of this license, see the COPYING file at the top level of this
@@ -14,77 +15,82 @@
*
* method:
*
- * open a file and queue a write to it with aio_write()
- * execute aio_cancel() on this file
- * check aio_cancel() is not -1
+ * open a pair of sockets and queue writes to them with aio_write()
+ * execute aio_cancel() on the socket
+ * check aio_cancel() returns zero or AIO_NOTCANCELED
+ * check that aio_error() returns ECANCELED for cancelable requests
* -> aio_cancel() works on fildes used with an aio command
*
- * we have no way to assert we generate "cancelable" AIO and thus to check
- * if it has been really canceled
+ * we queue enough writes to ensure that one of them will block
+ * on full socket buffer and the last one will be cancelable
*
*/
-#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <aio.h>
#include <time.h>
#include "posixtest.h"
-#include "tempfile.h"
+#include "aio_test.h"
#define TNAME "aio_cancel/2-1.c"
+#define WRITE_COUNT 8
+#define BLOCKED_TASK 2
+
+static int fds[2];
+static struct aiocb aiocb[WRITE_COUNT];
+
int main(void)
{
- char tmpfname[PATH_MAX];
-#define BUF_SIZE 1024
- char buf[BUF_SIZE];
- int fd, err;
- struct aiocb aiocb;
+ int i;
+ int ret;
if (sysconf(_SC_ASYNCHRONOUS_IO) < 200112L)
return PTS_UNSUPPORTED;
- PTS_GET_TMP_FILENAME(tmpfname, "pts_aio_cancel_2_1");
- unlink(tmpfname);
- fd = open(tmpfname, O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR);
- if (fd == -1) {
- printf(TNAME " Error at open(): %s\n", strerror(errno));
+ if (setup_aio(TNAME, fds, aiocb, WRITE_COUNT))
return PTS_UNRESOLVED;
- }
- unlink(tmpfname);
+ /* submit AIO req */
+ for (i = 0; i < WRITE_COUNT; i++) {
+ if (aio_write(&aiocb[i]) == -1) {
+ printf(TNAME " loop %d: Error at aio_write(): %s\n",
+ i, strerror(errno));
+ cleanup_aio(fds, aiocb, WRITE_COUNT);
+ return PTS_FAIL;
+ }
+ }
- memset(buf, 0xaa, BUF_SIZE);
- memset(&aiocb, 0, sizeof(struct aiocb));
- aiocb.aio_fildes = fd;
- aiocb.aio_buf = buf;
- aiocb.aio_nbytes = BUF_SIZE;
+ ret = aio_cancel(fds[0], NULL);
- if (aio_write(&aiocb) == -1) {
- printf(TNAME " Error at aio_write(): %s\n", strerror(errno));
+ if (ret == -1) {
+ printf(TNAME " Error at aio_cancel(): %s\n", strerror(errno));
+ cleanup_aio(fds, aiocb, WRITE_COUNT);
return PTS_FAIL;
}
- switch (aio_cancel(fd, NULL)) {
- case -1:
- printf(TNAME " Error at aio_cancel(): %s\n", strerror(errno));
+ if (ret != 0 && ret != AIO_NOTCANCELED) {
+ printf(TNAME " Unexpected aio_cancel() return value: %d\n",
+ ret);
+ cleanup_aio(fds, aiocb, WRITE_COUNT);
return PTS_FAIL;
- case AIO_NOTCANCELED:
- do {
- struct timespec completion_wait_ts = {0, 10000000};
- nanosleep(&completion_wait_ts, NULL);
- err = aio_error(&aiocb);
- } while (err == EINPROGRESS);
}
- close(fd);
+ for (i = BLOCKED_TASK + 1; i < WRITE_COUNT; i++) {
+ ret = aio_error(&aiocb[i]);
+
+ if (ret != ECANCELED) {
+ printf(TNAME " AIO request %d was not canceled: %s\n",
+ i, strerror(ret));
+ cleanup_aio(fds, aiocb, WRITE_COUNT);
+ return PTS_FAIL;
+ }
+ }
+
+ cleanup_aio(fds, aiocb, WRITE_COUNT);
printf("Test PASSED\n");
return PTS_PASS;
}
--
2.52.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 12+ messages in thread