[LTP] [PATCH 3/3] aio_cancel_2-1: Rewrite test

Martin Doucha mdoucha@suse.cz
Tue Feb 3 13:50:26 CET 2026


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



More information about the ltp mailing list