sqpoll-exec.c 2.7 KB

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