[LTP] [PATCH] lio_listio_2-1: Rewrite test
Martin Doucha
mdoucha@suse.cz
Thu Jan 15 18:18:46 CET 2026
The test schedules multiple async writes into a file and then hopes that
at least one will block long enough that a variable can be checked before
the completion signal arrives. Use a socket pair instead of file
to force async writes to block indefinitely. Then drain the socket after
the first signal check and wait for the signal.
Add cleanup helper function that will flush socket buffers, free allocated
memory and close the sockets. Also make setup and cleanup simpler
by statically allocating the aiocb structure array.
Signed-off-by: Martin Doucha <mdoucha@suse.cz>
---
Another race condition fix by filling socket pair buffers until they
block. Tested on kernel v4.4 and v6.12.
.../conformance/interfaces/lio_listio/2-1.c | 133 +++++++++++-------
1 file changed, 81 insertions(+), 52 deletions(-)
diff --git a/testcases/open_posix_testsuite/conformance/interfaces/lio_listio/2-1.c b/testcases/open_posix_testsuite/conformance/interfaces/lio_listio/2-1.c
index efcd5b3fc..b21c6d04d 100644
--- a/testcases/open_posix_testsuite/conformance/interfaces/lio_listio/2-1.c
+++ b/testcases/open_posix_testsuite/conformance/interfaces/lio_listio/2-1.c
@@ -13,30 +13,33 @@
*
* method:
*
- * - open a file for writing
+ * - open a socket pair
* - submit a list of writes to lio_listio in LIO_NOWAIT mode
* - check that upon return some I/Os are still running
+ * - drain the sockets
+ * - check that I/O finish signal was received
*
*/
-#include <sys/stat.h>
#include <aio.h>
#include <errno.h>
-#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <sys/socket.h>
#include "posixtest.h"
#include "tempfile.h"
#define TNAME "lio_listio/2-1.c"
-#define NUM_AIOCBS 256
-#define BUF_SIZE 1024
+#define NUM_AIOCBS 8
+static int fds[2];
+static struct aiocb aiocbs[NUM_AIOCBS];
+static char *bufs;
static volatile int received_all;
static void sigrt2_handler(int signum PTS_ATTRIBUTE_UNUSED,
@@ -46,54 +49,81 @@ static void sigrt2_handler(int signum PTS_ATTRIBUTE_UNUSED,
received_all = 1;
}
-int main(void)
+static void read_all(void)
+{
+ int i, ret;
+
+ for (i = 0; i < NUM_AIOCBS; i++) {
+ if (!aiocbs[i].aio_buf)
+ break;
+
+ ret = aio_error(&aiocbs[i]);
+
+ /* flush written data from the socket */
+ if (ret == 0 || ret == EINPROGRESS) {
+ read(fds[1], (void *)aiocbs[i].aio_buf,
+ aiocbs[i].aio_nbytes);
+ aiocbs[i].aio_buf = NULL;
+ }
+ }
+}
+
+static void cleanup(void)
{
- char tmpfname[PATH_MAX];
- int fd;
+ read_all();
+ free(bufs);
+ close(fds[0]);
+ close(fds[1]);
+}
- struct aiocb *aiocbs[NUM_AIOCBS];
- char *bufs;
+int main(void)
+{
+ struct aiocb *liocbs[NUM_AIOCBS];
struct sigaction action;
struct sigevent event;
int errors = 0;
int ret;
int err;
int i;
+ int bufsize;
+ socklen_t argsize = sizeof(bufsize);
if (sysconf(_SC_ASYNCHRONOUS_IO) < 200112L)
exit(PTS_UNSUPPORTED);
- PTS_GET_TMP_FILENAME(tmpfname, "pts_lio_listio_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));
- exit(PTS_UNRESOLVED);
+ ret = socketpair(AF_UNIX, SOCK_DGRAM, 0, fds);
+ if (ret == -1) {
+ printf(TNAME " Error creating sockets(): %s\n",
+ strerror(errno));
+ return PTS_UNRESOLVED;
}
- unlink(tmpfname);
+ 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;
+ }
- bufs = malloc(NUM_AIOCBS * BUF_SIZE);
+ /* Socket buffer size is twice the maximum message size */
+ bufsize /= 2;
+ bufs = malloc(NUM_AIOCBS * bufsize);
if (bufs == NULL) {
printf(TNAME " Error at malloc(): %s\n", strerror(errno));
- close(fd);
+ cleanup();
exit(PTS_UNRESOLVED);
}
/* Queue up a bunch of aio writes */
for (i = 0; i < NUM_AIOCBS; i++) {
-
- aiocbs[i] = malloc(sizeof(struct aiocb));
- memset(aiocbs[i], 0, sizeof(struct aiocb));
-
- aiocbs[i]->aio_fildes = fd;
- aiocbs[i]->aio_offset = i * BUF_SIZE;
- aiocbs[i]->aio_buf = &bufs[i * BUF_SIZE];
- aiocbs[i]->aio_nbytes = BUF_SIZE;
- aiocbs[i]->aio_lio_opcode = LIO_WRITE;
+ liocbs[i] = &aiocbs[i];
+ aiocbs[i].aio_fildes = fds[0];
+ aiocbs[i].aio_offset = i * bufsize;
+ aiocbs[i].aio_buf = &bufs[i * bufsize];
+ aiocbs[i].aio_nbytes = bufsize;
+ aiocbs[i].aio_lio_opcode = LIO_WRITE;
}
/* Use SIGRTMIN+2 for list completion */
@@ -108,53 +138,52 @@ int main(void)
sigaction(SIGRTMIN + 2, &action, NULL);
/* Submit request list */
- ret = lio_listio(LIO_NOWAIT, aiocbs, NUM_AIOCBS, &event);
+ ret = lio_listio(LIO_NOWAIT, liocbs, NUM_AIOCBS, &event);
if (ret) {
printf(TNAME " Error at lio_listio() %d: %s\n", errno,
- strerror(errno));
- for (i = 0; i < NUM_AIOCBS; i++)
- free(aiocbs[i]);
- free(bufs);
- close(fd);
+ strerror(errno));
+ /* Clear the aiocbs or cleanup() will get stuck */
+ memset(aiocbs, 0, NUM_AIOCBS * sizeof(struct aiocb));
+ cleanup();
exit(PTS_FAIL);
}
if (received_all != 0) {
printf(TNAME
- " Error lio_listio() waited for list completion\n");
- for (i = 0; i < NUM_AIOCBS; i++)
- free(aiocbs[i]);
- free(bufs);
- close(fd);
+ " Error lio_listio() signaled completion too early\n");
+ cleanup();
exit(PTS_FAIL);
}
- while (received_all == 0)
+ read_all();
+
+ for (i = 0; i < 5 && !received_all; i++)
sleep(1);
+ if (received_all == 0) {
+ printf(TNAME " Test did not receive I/O completion signal\n");
+ cleanup();
+ exit(PTS_FAIL);
+ }
+
/* Check return code and free things */
for (i = 0; i < NUM_AIOCBS; i++) {
- err = aio_error(aiocbs[i]);
- ret = aio_return(aiocbs[i]);
+ err = aio_error(&aiocbs[i]);
+ ret = aio_return(&aiocbs[i]);
- if ((err != 0) && (ret != BUF_SIZE)) {
+ if ((err != 0) && (ret != bufsize)) {
printf(TNAME " req %d: error = %d - return = %d\n", i,
- err, ret);
+ err, ret);
errors++;
}
-
- free(aiocbs[i]);
}
- free(bufs);
-
- close(fd);
+ cleanup();
if (errors != 0)
exit(PTS_FAIL);
printf(TNAME " PASSED\n");
-
return PTS_PASS;
}
--
2.51.0
More information about the ltp
mailing list