kallsyms.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. #include "../config-host.h"
  2. /* SPDX-License-Identifier: MIT */
  3. /*
  4. * Description: read /proc/kallsyms. Mostly just here so that fops->read() can
  5. * get exercised, with and without registered buffers
  6. */
  7. #include <errno.h>
  8. #include <stdio.h>
  9. #include <unistd.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <fcntl.h>
  13. #include <sys/types.h>
  14. #include <poll.h>
  15. #include <sys/eventfd.h>
  16. #include <sys/resource.h>
  17. #include "helpers.h"
  18. #include "liburing.h"
  19. #define FILE_SIZE (8 * 1024)
  20. #define BS 8192
  21. #define BUFFERS (FILE_SIZE / BS)
  22. static struct iovec *vecs;
  23. static int warned;
  24. static int __test_io(const char *file, struct io_uring *ring, int fixed, int nonvec)
  25. {
  26. struct io_uring_sqe *sqe;
  27. struct io_uring_cqe *cqe;
  28. int open_flags;
  29. int i, fd = -1, ret;
  30. off_t offset;
  31. open_flags = O_RDONLY;
  32. if (fixed) {
  33. ret = t_register_buffers(ring, vecs, BUFFERS);
  34. if (ret == T_SETUP_SKIP)
  35. return 0;
  36. if (ret != T_SETUP_OK) {
  37. fprintf(stderr, "buffer reg failed: %d\n", ret);
  38. goto err;
  39. }
  40. }
  41. fd = open(file, open_flags);
  42. if (fd < 0) {
  43. if (errno == EINVAL || errno == EPERM || errno == ENOENT)
  44. return 0;
  45. perror("file open");
  46. goto err;
  47. }
  48. offset = 0;
  49. for (i = 0; i < BUFFERS; i++) {
  50. int do_fixed = fixed;
  51. sqe = io_uring_get_sqe(ring);
  52. if (!sqe) {
  53. fprintf(stderr, "sqe get failed\n");
  54. goto err;
  55. }
  56. if (fixed && (i & 1))
  57. do_fixed = 0;
  58. if (do_fixed) {
  59. io_uring_prep_read_fixed(sqe, fd, vecs[i].iov_base,
  60. vecs[i].iov_len, offset, i);
  61. } else if (nonvec) {
  62. io_uring_prep_read(sqe, fd, vecs[i].iov_base,
  63. vecs[i].iov_len, offset);
  64. } else {
  65. io_uring_prep_readv(sqe, fd, &vecs[i], 1, offset);
  66. }
  67. sqe->user_data = i;
  68. offset += BS;
  69. }
  70. ret = io_uring_submit(ring);
  71. if (ret != BUFFERS) {
  72. fprintf(stderr, "submit got %d, wanted %d\n", ret, BUFFERS);
  73. goto err;
  74. }
  75. for (i = 0; i < BUFFERS; i++) {
  76. ret = io_uring_wait_cqe(ring, &cqe);
  77. if (ret) {
  78. fprintf(stderr, "wait_cqe=%d\n", ret);
  79. goto err;
  80. }
  81. if (cqe->res == -EINVAL && nonvec) {
  82. if (!warned) {
  83. fprintf(stdout, "Non-vectored IO not "
  84. "supported, skipping\n");
  85. warned = 1;
  86. }
  87. }
  88. io_uring_cqe_seen(ring, cqe);
  89. }
  90. if (fixed) {
  91. ret = io_uring_unregister_buffers(ring);
  92. if (ret) {
  93. fprintf(stderr, "buffer unreg failed: %d\n", ret);
  94. goto err;
  95. }
  96. }
  97. close(fd);
  98. return 0;
  99. err:
  100. if (fd != -1)
  101. close(fd);
  102. return 1;
  103. }
  104. static int test_io(const char *file, int fixed, int nonvec)
  105. {
  106. struct io_uring ring;
  107. int ret, ring_flags = 0;
  108. ret = t_create_ring(64, &ring, ring_flags);
  109. if (ret == T_SETUP_SKIP)
  110. return 0;
  111. if (ret != T_SETUP_OK) {
  112. fprintf(stderr, "ring create failed: %d\n", ret);
  113. return 1;
  114. }
  115. ret = __test_io(file, &ring, fixed, nonvec);
  116. io_uring_queue_exit(&ring);
  117. return ret;
  118. }
  119. static int has_nonvec_read(void)
  120. {
  121. struct io_uring_probe *p;
  122. struct io_uring ring;
  123. int ret;
  124. ret = io_uring_queue_init(1, &ring, 0);
  125. if (ret) {
  126. fprintf(stderr, "queue init failed: %d\n", ret);
  127. exit(ret);
  128. }
  129. p = t_calloc(1, sizeof(*p) + 256 * sizeof(struct io_uring_probe_op));
  130. ret = io_uring_register_probe(&ring, p, 256);
  131. /* if we don't have PROBE_REGISTER, we don't have OP_READ/WRITE */
  132. if (ret == -EINVAL) {
  133. out:
  134. io_uring_queue_exit(&ring);
  135. free(p);
  136. return 0;
  137. } else if (ret) {
  138. fprintf(stderr, "register_probe: %d\n", ret);
  139. goto out;
  140. }
  141. if (p->ops_len <= IORING_OP_READ)
  142. goto out;
  143. if (!(p->ops[IORING_OP_READ].flags & IO_URING_OP_SUPPORTED))
  144. goto out;
  145. io_uring_queue_exit(&ring);
  146. free(p);
  147. return 1;
  148. }
  149. int main(int argc, char *argv[])
  150. {
  151. int ret, nonvec;
  152. if (argc > 1)
  153. return T_EXIT_SKIP;
  154. vecs = t_create_buffers(BUFFERS, BS);
  155. /* if we don't have nonvec read, skip testing that */
  156. nonvec = has_nonvec_read();
  157. if (nonvec) {
  158. ret = test_io("/proc/kallsyms", 0, 0);
  159. if (ret)
  160. goto err;
  161. }
  162. ret = test_io("/proc/kallsyms", 0, 1);
  163. if (ret)
  164. goto err;
  165. if (nonvec) {
  166. ret = test_io("/proc/kallsyms", 1, 0);
  167. if (ret)
  168. goto err;
  169. }
  170. ret = test_io("/proc/kallsyms", 1, 1);
  171. if (ret)
  172. goto err;
  173. return 0;
  174. err:
  175. fprintf(stderr, "Reading kallsyms failed\n");
  176. return 1;
  177. }