Skip to content

Commit 1472f4f

Browse files
mdouchapevik
authored andcommitted
lio_listio_2-1: Rewrite test
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. Link: https://lore.kernel.org/ltp/20260115171847.28091-1-mdoucha@suse.cz/ Reviewed-by: Petr Vorel <pvorel@suse.cz> Signed-off-by: Martin Doucha <mdoucha@suse.cz>
1 parent bb7f057 commit 1472f4f

1 file changed

Lines changed: 82 additions & 52 deletions

File tree

  • testcases/open_posix_testsuite/conformance/interfaces/lio_listio
Lines changed: 82 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 2004, Bull SA. All rights reserved.
3+
* Copyright (c) 2025 SUSE LLC
34
* Created by: Laurent.Vivier@bull.net
45
* This file is licensed under the GPL license. For the full content
56
* of this license, see the COPYING file at the top level of this
@@ -13,30 +14,33 @@
1314
*
1415
* method:
1516
*
16-
* - open a file for writing
17+
* - open a socket pair
1718
* - submit a list of writes to lio_listio in LIO_NOWAIT mode
1819
* - check that upon return some I/Os are still running
20+
* - drain the sockets
21+
* - check that I/O finish signal was received
1922
*
2023
*/
2124

22-
#include <sys/stat.h>
2325
#include <aio.h>
2426
#include <errno.h>
25-
#include <fcntl.h>
2627
#include <signal.h>
2728
#include <stdio.h>
2829
#include <stdlib.h>
2930
#include <string.h>
3031
#include <unistd.h>
32+
#include <sys/socket.h>
3133

3234
#include "posixtest.h"
3335
#include "tempfile.h"
3436

3537
#define TNAME "lio_listio/2-1.c"
3638

37-
#define NUM_AIOCBS 256
38-
#define BUF_SIZE 1024
39+
#define NUM_AIOCBS 8
3940

41+
static int fds[2];
42+
static struct aiocb aiocbs[NUM_AIOCBS];
43+
static char *bufs;
4044
static volatile int received_all;
4145

4246
static void sigrt2_handler(int signum PTS_ATTRIBUTE_UNUSED,
@@ -46,54 +50,81 @@ static void sigrt2_handler(int signum PTS_ATTRIBUTE_UNUSED,
4650
received_all = 1;
4751
}
4852

49-
int main(void)
53+
static void read_all(void)
54+
{
55+
int i, ret;
56+
57+
for (i = 0; i < NUM_AIOCBS; i++) {
58+
if (!aiocbs[i].aio_buf)
59+
break;
60+
61+
ret = aio_error(&aiocbs[i]);
62+
63+
/* flush written data from the socket */
64+
if (ret == 0 || ret == EINPROGRESS) {
65+
read(fds[1], (void *)aiocbs[i].aio_buf,
66+
aiocbs[i].aio_nbytes);
67+
aiocbs[i].aio_buf = NULL;
68+
}
69+
}
70+
}
71+
72+
static void cleanup(void)
5073
{
51-
char tmpfname[PATH_MAX];
52-
int fd;
74+
read_all();
75+
free(bufs);
76+
close(fds[0]);
77+
close(fds[1]);
78+
}
5379

54-
struct aiocb *aiocbs[NUM_AIOCBS];
55-
char *bufs;
80+
int main(void)
81+
{
82+
struct aiocb *liocbs[NUM_AIOCBS];
5683
struct sigaction action;
5784
struct sigevent event;
5885
int errors = 0;
5986
int ret;
6087
int err;
6188
int i;
89+
int bufsize;
90+
socklen_t argsize = sizeof(bufsize);
6291

6392
if (sysconf(_SC_ASYNCHRONOUS_IO) < 200112L)
6493
exit(PTS_UNSUPPORTED);
6594

66-
PTS_GET_TMP_FILENAME(tmpfname, "pts_lio_listio_2_1");
67-
unlink(tmpfname);
68-
69-
fd = open(tmpfname, O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR);
70-
71-
if (fd == -1) {
72-
printf(TNAME " Error at open(): %s\n", strerror(errno));
73-
exit(PTS_UNRESOLVED);
95+
ret = socketpair(AF_UNIX, SOCK_DGRAM, 0, fds);
96+
if (ret == -1) {
97+
printf(TNAME " Error creating sockets(): %s\n",
98+
strerror(errno));
99+
return PTS_UNRESOLVED;
74100
}
75101

76-
unlink(tmpfname);
102+
ret = getsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, &bufsize, &argsize);
103+
if (ret == -1) {
104+
printf(TNAME " Error reading socket buffer size: %s\n",
105+
strerror(errno));
106+
cleanup();
107+
return PTS_UNRESOLVED;
108+
}
77109

78-
bufs = malloc(NUM_AIOCBS * BUF_SIZE);
110+
/* Socket buffer size is twice the maximum message size */
111+
bufsize /= 2;
112+
bufs = malloc(NUM_AIOCBS * bufsize);
79113

80114
if (bufs == NULL) {
81115
printf(TNAME " Error at malloc(): %s\n", strerror(errno));
82-
close(fd);
116+
cleanup();
83117
exit(PTS_UNRESOLVED);
84118
}
85119

86120
/* Queue up a bunch of aio writes */
87121
for (i = 0; i < NUM_AIOCBS; i++) {
88-
89-
aiocbs[i] = malloc(sizeof(struct aiocb));
90-
memset(aiocbs[i], 0, sizeof(struct aiocb));
91-
92-
aiocbs[i]->aio_fildes = fd;
93-
aiocbs[i]->aio_offset = i * BUF_SIZE;
94-
aiocbs[i]->aio_buf = &bufs[i * BUF_SIZE];
95-
aiocbs[i]->aio_nbytes = BUF_SIZE;
96-
aiocbs[i]->aio_lio_opcode = LIO_WRITE;
122+
liocbs[i] = &aiocbs[i];
123+
aiocbs[i].aio_fildes = fds[0];
124+
aiocbs[i].aio_offset = i * bufsize;
125+
aiocbs[i].aio_buf = &bufs[i * bufsize];
126+
aiocbs[i].aio_nbytes = bufsize;
127+
aiocbs[i].aio_lio_opcode = LIO_WRITE;
97128
}
98129

99130
/* Use SIGRTMIN+2 for list completion */
@@ -108,53 +139,52 @@ int main(void)
108139
sigaction(SIGRTMIN + 2, &action, NULL);
109140

110141
/* Submit request list */
111-
ret = lio_listio(LIO_NOWAIT, aiocbs, NUM_AIOCBS, &event);
142+
ret = lio_listio(LIO_NOWAIT, liocbs, NUM_AIOCBS, &event);
112143

113144
if (ret) {
114145
printf(TNAME " Error at lio_listio() %d: %s\n", errno,
115-
strerror(errno));
116-
for (i = 0; i < NUM_AIOCBS; i++)
117-
free(aiocbs[i]);
118-
free(bufs);
119-
close(fd);
146+
strerror(errno));
147+
/* Clear the aiocbs or cleanup() will get stuck */
148+
memset(aiocbs, 0, NUM_AIOCBS * sizeof(struct aiocb));
149+
cleanup();
120150
exit(PTS_FAIL);
121151
}
122152

123153
if (received_all != 0) {
124154
printf(TNAME
125-
" Error lio_listio() waited for list completion\n");
126-
for (i = 0; i < NUM_AIOCBS; i++)
127-
free(aiocbs[i]);
128-
free(bufs);
129-
close(fd);
155+
" Error lio_listio() signaled completion too early\n");
156+
cleanup();
130157
exit(PTS_FAIL);
131158
}
132159

133-
while (received_all == 0)
160+
read_all();
161+
162+
for (i = 0; i < 5 && !received_all; i++)
134163
sleep(1);
135164

165+
if (received_all == 0) {
166+
printf(TNAME " Test did not receive I/O completion signal\n");
167+
cleanup();
168+
exit(PTS_FAIL);
169+
}
170+
136171
/* Check return code and free things */
137172
for (i = 0; i < NUM_AIOCBS; i++) {
138-
err = aio_error(aiocbs[i]);
139-
ret = aio_return(aiocbs[i]);
173+
err = aio_error(&aiocbs[i]);
174+
ret = aio_return(&aiocbs[i]);
140175

141-
if ((err != 0) && (ret != BUF_SIZE)) {
176+
if ((err != 0) && (ret != bufsize)) {
142177
printf(TNAME " req %d: error = %d - return = %d\n", i,
143-
err, ret);
178+
err, ret);
144179
errors++;
145180
}
146-
147-
free(aiocbs[i]);
148181
}
149182

150-
free(bufs);
151-
152-
close(fd);
183+
cleanup();
153184

154185
if (errors != 0)
155186
exit(PTS_FAIL);
156187

157188
printf(TNAME " PASSED\n");
158-
159189
return PTS_PASS;
160190
}

0 commit comments

Comments
 (0)