1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
/* SPDX-License-Identifier: MIT */
/*
* Description: Check that closing a file with SQPOLL has it immediately closed
* upon receiving the CQE for the close. The 6.9 kernel had a bug
* where SQPOLL would not run kernel wide task_work when running the
* private task_work, which would defer the close if this was the
* final close of the file.
*/
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "helpers.h"
#include "liburing.h"
static int fill_exec_target(char *dst, char *path)
{
struct stat sb;
/*
* Should either be ./exec-target.t or test/exec-target.t
*/
sprintf(dst, "%s", path);
return stat(dst, &sb);
}
static int test_exec(struct io_uring *ring, char * const argv[])
{
char prog_path[PATH_MAX];
struct io_uring_sqe *sqe;
struct io_uring_cqe *cqe;
int ret, wstatus, fd;
pid_t p;
if (fill_exec_target(prog_path, "./exec-target.t") &&
fill_exec_target(prog_path, "test/exec-target.t")) {
fprintf(stdout, "Can't find exec-target, skipping\n");
return 0;
}
sqe = io_uring_get_sqe(ring);
io_uring_prep_openat(sqe, AT_FDCWD, prog_path, O_WRONLY, 0);
sqe->user_data = 0;
io_uring_submit(ring);
ret = io_uring_wait_cqe(ring, &cqe);
if (ret) {
fprintf(stderr, "wait cqe %d\n", ret);
return 1;
}
if (cqe->res < 0) {
fprintf(stderr, "open: %d\n", cqe->res);
return 1;
}
fd = cqe->res;
io_uring_cqe_seen(ring, cqe);
sqe = io_uring_get_sqe(ring);
io_uring_prep_close(sqe, fd);
sqe->user_data = 1;
io_uring_submit(ring);
ret = io_uring_wait_cqe(ring, &cqe);
if (ret) {
fprintf(stderr, "wait cqe %d\n", ret);
return 1;
}
if (cqe->res < 0) {
fprintf(stderr, "close: %d\n", cqe->res);
return 1;
}
io_uring_cqe_seen(ring, cqe);
p = fork();
if (p == -1) {
fprintf(stderr, "fork() failed\n");
return 1;
}
if (p == 0) {
/* file should be closed, try exec'ing it */
ret = execve(prog_path, argv, NULL);
if (ret) {
fprintf(stderr, "exec failed: %s\n", strerror(errno));
exit(1);
}
}
if (waitpid(p, &wstatus, 0) == (pid_t)-1) {
perror("waitpid()");
return 1;
}
if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus))
return 1;
return 0;
}
int main(int argc, char * const argv[])
{
struct io_uring_params p = { .flags = IORING_SETUP_SQPOLL, };
struct io_uring ring;
int ret, i;
if (argc > 1)
return T_EXIT_SKIP;
ret = t_create_ring_params(8, &ring, &p);
if (ret == T_SETUP_SKIP)
return T_EXIT_SKIP;
else if (ret != T_SETUP_OK)
return T_EXIT_FAIL;
for (i = 0; i < 20; i++) {
ret = test_exec(&ring, argv);
if (ret) {
fprintf(stderr, "test_exec failed\n");
return ret;
}
}
return T_EXIT_PASS;
}
|