read-write.c 22 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079
  1. #include "../config-host.h"
  2. /* SPDX-License-Identifier: MIT */
  3. /*
  4. * Description: basic read/write tests with buffered, O_DIRECT, and SQPOLL
  5. */
  6. #include <errno.h>
  7. #include <stdio.h>
  8. #include <unistd.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <fcntl.h>
  12. #include <sys/types.h>
  13. #include <poll.h>
  14. #include <sys/eventfd.h>
  15. #include <sys/resource.h>
  16. #include "helpers.h"
  17. #include "liburing.h"
  18. #include "../src/syscall.h"
  19. #define FILE_SIZE (256 * 1024)
  20. #define BS 8192
  21. #define BUFFERS (FILE_SIZE / BS)
  22. static struct iovec *vecs;
  23. static int no_read;
  24. static int no_buf_select;
  25. static int no_buf_copy;
  26. static int warned;
  27. static int create_nonaligned_buffers(void)
  28. {
  29. int i;
  30. vecs = t_malloc(BUFFERS * sizeof(struct iovec));
  31. for (i = 0; i < BUFFERS; i++) {
  32. char *p = t_malloc(3 * BS);
  33. if (!p)
  34. return 1;
  35. vecs[i].iov_base = p + (rand() % BS);
  36. vecs[i].iov_len = 1 + (rand() % BS);
  37. }
  38. return 0;
  39. }
  40. static int _test_io(const char *file, struct io_uring *ring, int write,
  41. int buffered, int sqthread, int fixed, int nonvec,
  42. int buf_select, int seq, int exp_len)
  43. {
  44. struct io_uring_sqe *sqe;
  45. struct io_uring_cqe *cqe;
  46. int open_flags;
  47. int i, fd = -1, ret;
  48. off_t offset;
  49. #ifdef VERBOSE
  50. fprintf(stdout, "%s: start %d/%d/%d/%d/%d: ", __FUNCTION__, write,
  51. buffered, sqthread,
  52. fixed, nonvec);
  53. #endif
  54. if (write)
  55. open_flags = O_WRONLY;
  56. else
  57. open_flags = O_RDONLY;
  58. if (!buffered)
  59. open_flags |= O_DIRECT;
  60. if (fixed == 1) {
  61. ret = t_register_buffers(ring, vecs, BUFFERS);
  62. if (ret == T_SETUP_SKIP)
  63. return 0;
  64. if (ret != T_SETUP_OK) {
  65. fprintf(stderr, "buffer reg failed: %d\n", ret);
  66. goto err;
  67. }
  68. }
  69. fd = open(file, open_flags);
  70. if (fd < 0) {
  71. if (errno == EINVAL || errno == EPERM || errno == EACCES)
  72. return 0;
  73. perror("file open");
  74. goto err;
  75. }
  76. if (sqthread) {
  77. ret = io_uring_register_files(ring, &fd, 1);
  78. if (ret) {
  79. fprintf(stderr, "file reg failed: %d\n", ret);
  80. goto err;
  81. }
  82. }
  83. offset = 0;
  84. for (i = 0; i < BUFFERS; i++) {
  85. sqe = io_uring_get_sqe(ring);
  86. if (!sqe) {
  87. fprintf(stderr, "sqe get failed\n");
  88. goto err;
  89. }
  90. if (!seq)
  91. offset = BS * (rand() % BUFFERS);
  92. if (write) {
  93. int do_fixed = fixed;
  94. int use_fd = fd;
  95. if (sqthread)
  96. use_fd = 0;
  97. if (fixed && (i & 1))
  98. do_fixed = 0;
  99. if (do_fixed) {
  100. io_uring_prep_write_fixed(sqe, use_fd, vecs[i].iov_base,
  101. vecs[i].iov_len,
  102. offset, i);
  103. } else if (nonvec) {
  104. io_uring_prep_write(sqe, use_fd, vecs[i].iov_base,
  105. vecs[i].iov_len, offset);
  106. } else {
  107. io_uring_prep_writev(sqe, use_fd, &vecs[i], 1,
  108. offset);
  109. }
  110. } else {
  111. int do_fixed = fixed;
  112. int use_fd = fd;
  113. if (sqthread)
  114. use_fd = 0;
  115. if (fixed && (i & 1))
  116. do_fixed = 0;
  117. if (do_fixed) {
  118. io_uring_prep_read_fixed(sqe, use_fd, vecs[i].iov_base,
  119. vecs[i].iov_len,
  120. offset, i);
  121. } else if (nonvec) {
  122. io_uring_prep_read(sqe, use_fd, vecs[i].iov_base,
  123. vecs[i].iov_len, offset);
  124. } else {
  125. io_uring_prep_readv(sqe, use_fd, &vecs[i], 1,
  126. offset);
  127. }
  128. }
  129. sqe->user_data = i;
  130. if (sqthread)
  131. sqe->flags |= IOSQE_FIXED_FILE;
  132. if (buf_select) {
  133. if (nonvec)
  134. sqe->addr = 0;
  135. sqe->flags |= IOSQE_BUFFER_SELECT;
  136. sqe->buf_group = buf_select;
  137. }
  138. if (seq)
  139. offset += BS;
  140. }
  141. ret = io_uring_submit(ring);
  142. if (ret != BUFFERS) {
  143. fprintf(stderr, "submit got %d, wanted %d\n", ret, BUFFERS);
  144. goto err;
  145. }
  146. for (i = 0; i < BUFFERS; i++) {
  147. ret = io_uring_wait_cqe(ring, &cqe);
  148. if (ret) {
  149. fprintf(stderr, "wait_cqe=%d\n", ret);
  150. goto err;
  151. }
  152. if (cqe->res == -EINVAL && nonvec) {
  153. if (!warned) {
  154. fprintf(stdout, "Non-vectored IO not "
  155. "supported, skipping\n");
  156. warned = 1;
  157. no_read = 1;
  158. }
  159. } else if (exp_len == -1) {
  160. int iov_len = vecs[cqe->user_data].iov_len;
  161. if (cqe->res != iov_len) {
  162. fprintf(stderr, "cqe res %d, wanted %d\n",
  163. cqe->res, iov_len);
  164. goto err;
  165. }
  166. } else if (cqe->res != exp_len) {
  167. fprintf(stderr, "cqe res %d, wanted %d\n", cqe->res, exp_len);
  168. goto err;
  169. }
  170. if (buf_select && exp_len == BS) {
  171. int bid = cqe->flags >> 16;
  172. unsigned char *ptr = vecs[bid].iov_base;
  173. int j;
  174. for (j = 0; j < BS; j++) {
  175. if (ptr[j] == cqe->user_data)
  176. continue;
  177. fprintf(stderr, "Data mismatch! bid=%d, "
  178. "wanted=%d, got=%d\n", bid,
  179. (int)cqe->user_data, ptr[j]);
  180. return 1;
  181. }
  182. }
  183. io_uring_cqe_seen(ring, cqe);
  184. }
  185. if (sqthread) {
  186. ret = io_uring_unregister_files(ring);
  187. if (ret) {
  188. fprintf(stderr, "file unreg failed: %d\n", ret);
  189. goto err;
  190. }
  191. }
  192. close(fd);
  193. #ifdef VERBOSE
  194. fprintf(stdout, "PASS\n");
  195. #endif
  196. return 0;
  197. err:
  198. #ifdef VERBOSE
  199. fprintf(stderr, "FAILED\n");
  200. #endif
  201. if (fd != -1)
  202. close(fd);
  203. return 1;
  204. }
  205. static int __test_io(const char *file, struct io_uring *ring, int write,
  206. int buffered, int sqthread, int fixed, int nonvec,
  207. int buf_select, int seq, int exp_len)
  208. {
  209. int ret;
  210. ret = _test_io(file, ring, write, buffered, sqthread, fixed, nonvec,
  211. buf_select, seq, exp_len);
  212. if (ret)
  213. return ret;
  214. if (fixed) {
  215. struct io_uring ring2;
  216. int ring_flags = 0;
  217. if (no_buf_copy)
  218. return 0;
  219. if (sqthread)
  220. ring_flags = IORING_SETUP_SQPOLL;
  221. ret = t_create_ring(64, &ring2, ring_flags);
  222. if (ret == T_SETUP_SKIP)
  223. return 0;
  224. if (ret != T_SETUP_OK) {
  225. fprintf(stderr, "ring create failed: %d\n", ret);
  226. return 1;
  227. }
  228. ret = io_uring_clone_buffers(&ring2, ring);
  229. if (ret) {
  230. if (ret == -EINVAL) {
  231. no_buf_copy = 1;
  232. io_uring_queue_exit(&ring2);
  233. return 0;
  234. }
  235. fprintf(stderr, "copy buffers: %d\n", ret);
  236. return ret;
  237. }
  238. ret = _test_io(file, &ring2, write, buffered, sqthread, 2,
  239. nonvec, buf_select, seq, exp_len);
  240. if (ret)
  241. return ret;
  242. ret = io_uring_unregister_buffers(ring);
  243. if (ret) {
  244. fprintf(stderr, "buffer unreg failed: %d\n", ret);
  245. return ret;
  246. }
  247. ret = io_uring_unregister_buffers(&ring2);
  248. if (ret) {
  249. fprintf(stderr, "buffer copy unreg failed: %d\n", ret);
  250. return ret;
  251. }
  252. io_uring_queue_exit(&ring2);
  253. }
  254. return ret;
  255. }
  256. static int test_io(const char *file, int write, int buffered, int sqthread,
  257. int fixed, int nonvec, int exp_len)
  258. {
  259. struct io_uring ring;
  260. int ret, ring_flags = 0;
  261. if (sqthread)
  262. ring_flags = IORING_SETUP_SQPOLL;
  263. ret = t_create_ring(64, &ring, ring_flags);
  264. if (ret == T_SETUP_SKIP)
  265. return 0;
  266. if (ret != T_SETUP_OK) {
  267. fprintf(stderr, "ring create failed: %d\n", ret);
  268. return 1;
  269. }
  270. ret = __test_io(file, &ring, write, buffered, sqthread, fixed, nonvec,
  271. 0, 0, exp_len);
  272. io_uring_queue_exit(&ring);
  273. return ret;
  274. }
  275. static int read_poll_link(const char *file)
  276. {
  277. struct __kernel_timespec ts;
  278. struct io_uring_sqe *sqe;
  279. struct io_uring_cqe *cqe;
  280. struct io_uring ring;
  281. int i, fd, ret, fds[2];
  282. ret = io_uring_queue_init(8, &ring, 0);
  283. if (ret)
  284. return ret;
  285. fd = open(file, O_WRONLY);
  286. if (fd < 0) {
  287. if (errno == EACCES || errno == EPERM)
  288. return T_EXIT_SKIP;
  289. perror("open");
  290. return 1;
  291. }
  292. if (pipe(fds)) {
  293. perror("pipe");
  294. return 1;
  295. }
  296. sqe = io_uring_get_sqe(&ring);
  297. io_uring_prep_writev(sqe, fd, &vecs[0], 1, 0);
  298. sqe->flags |= IOSQE_IO_LINK;
  299. sqe->user_data = 1;
  300. sqe = io_uring_get_sqe(&ring);
  301. io_uring_prep_poll_add(sqe, fds[0], POLLIN);
  302. sqe->flags |= IOSQE_IO_LINK;
  303. sqe->user_data = 2;
  304. ts.tv_sec = 1;
  305. ts.tv_nsec = 0;
  306. sqe = io_uring_get_sqe(&ring);
  307. io_uring_prep_link_timeout(sqe, &ts, 0);
  308. sqe->user_data = 3;
  309. ret = io_uring_submit(&ring);
  310. if (ret != 3) {
  311. fprintf(stderr, "submitted %d\n", ret);
  312. return 1;
  313. }
  314. for (i = 0; i < 3; i++) {
  315. ret = io_uring_wait_cqe(&ring, &cqe);
  316. if (ret) {
  317. fprintf(stderr, "wait_cqe=%d\n", ret);
  318. return 1;
  319. }
  320. io_uring_cqe_seen(&ring, cqe);
  321. }
  322. return 0;
  323. }
  324. static int has_nonvec_read(void)
  325. {
  326. struct io_uring_probe *p;
  327. struct io_uring ring;
  328. int ret;
  329. ret = io_uring_queue_init(1, &ring, 0);
  330. if (ret) {
  331. fprintf(stderr, "queue init failed: %d\n", ret);
  332. exit(ret);
  333. }
  334. p = t_calloc(1, sizeof(*p) + 256 * sizeof(struct io_uring_probe_op));
  335. ret = io_uring_register_probe(&ring, p, 256);
  336. /* if we don't have PROBE_REGISTER, we don't have OP_READ/WRITE */
  337. if (ret == -EINVAL) {
  338. out:
  339. io_uring_queue_exit(&ring);
  340. return 0;
  341. } else if (ret) {
  342. fprintf(stderr, "register_probe: %d\n", ret);
  343. goto out;
  344. }
  345. if (p->ops_len <= IORING_OP_READ)
  346. goto out;
  347. if (!(p->ops[IORING_OP_READ].flags & IO_URING_OP_SUPPORTED))
  348. goto out;
  349. io_uring_queue_exit(&ring);
  350. free(p);
  351. return 1;
  352. }
  353. static int test_eventfd_read(void)
  354. {
  355. struct io_uring ring;
  356. int fd, ret;
  357. eventfd_t event;
  358. struct io_uring_sqe *sqe;
  359. struct io_uring_cqe *cqe;
  360. if (no_read)
  361. return 0;
  362. ret = io_uring_queue_init(8, &ring, 0);
  363. if (ret)
  364. return ret;
  365. fd = eventfd(1, 0);
  366. if (fd < 0) {
  367. perror("eventfd");
  368. return 1;
  369. }
  370. sqe = io_uring_get_sqe(&ring);
  371. io_uring_prep_read(sqe, fd, &event, sizeof(eventfd_t), 0);
  372. ret = io_uring_submit(&ring);
  373. if (ret != 1) {
  374. fprintf(stderr, "submitted %d\n", ret);
  375. return 1;
  376. }
  377. eventfd_write(fd, 1);
  378. ret = io_uring_wait_cqe(&ring, &cqe);
  379. if (ret) {
  380. fprintf(stderr, "wait_cqe=%d\n", ret);
  381. return 1;
  382. }
  383. if (cqe->res == -EINVAL) {
  384. fprintf(stdout, "eventfd IO not supported, skipping\n");
  385. } else if (cqe->res != sizeof(eventfd_t)) {
  386. fprintf(stderr, "cqe res %d, wanted %d\n", cqe->res,
  387. (int) sizeof(eventfd_t));
  388. return 1;
  389. }
  390. io_uring_cqe_seen(&ring, cqe);
  391. return 0;
  392. }
  393. static int test_buf_select_short(const char *filename, int nonvec)
  394. {
  395. struct io_uring_sqe *sqe;
  396. struct io_uring_cqe *cqe;
  397. struct io_uring ring;
  398. int ret, i, exp_len;
  399. if (no_buf_select)
  400. return 0;
  401. ret = io_uring_queue_init(64, &ring, 0);
  402. if (ret) {
  403. fprintf(stderr, "ring create failed: %d\n", ret);
  404. return 1;
  405. }
  406. exp_len = 0;
  407. for (i = 0; i < BUFFERS; i++) {
  408. sqe = io_uring_get_sqe(&ring);
  409. io_uring_prep_provide_buffers(sqe, vecs[i].iov_base,
  410. vecs[i].iov_len / 2, 1, 1, i);
  411. if (!exp_len)
  412. exp_len = vecs[i].iov_len / 2;
  413. }
  414. ret = io_uring_submit(&ring);
  415. if (ret != BUFFERS) {
  416. fprintf(stderr, "submit: %d\n", ret);
  417. return -1;
  418. }
  419. for (i = 0; i < BUFFERS; i++) {
  420. ret = io_uring_wait_cqe(&ring, &cqe);
  421. if (cqe->res < 0) {
  422. fprintf(stderr, "cqe->res=%d\n", cqe->res);
  423. return 1;
  424. }
  425. io_uring_cqe_seen(&ring, cqe);
  426. }
  427. ret = __test_io(filename, &ring, 0, 0, 0, 0, nonvec, 1, 1, exp_len);
  428. io_uring_queue_exit(&ring);
  429. return ret;
  430. }
  431. static int provide_buffers_iovec(struct io_uring *ring, int bgid)
  432. {
  433. struct io_uring_sqe *sqe;
  434. struct io_uring_cqe *cqe;
  435. int i, ret;
  436. for (i = 0; i < BUFFERS; i++) {
  437. sqe = io_uring_get_sqe(ring);
  438. io_uring_prep_provide_buffers(sqe, vecs[i].iov_base,
  439. vecs[i].iov_len, 1, bgid, i);
  440. }
  441. ret = io_uring_submit(ring);
  442. if (ret != BUFFERS) {
  443. fprintf(stderr, "submit: %d\n", ret);
  444. return -1;
  445. }
  446. for (i = 0; i < BUFFERS; i++) {
  447. ret = io_uring_wait_cqe(ring, &cqe);
  448. if (ret) {
  449. fprintf(stderr, "wait_cqe=%d\n", ret);
  450. return 1;
  451. }
  452. if (cqe->res < 0) {
  453. fprintf(stderr, "cqe->res=%d\n", cqe->res);
  454. return 1;
  455. }
  456. io_uring_cqe_seen(ring, cqe);
  457. }
  458. return 0;
  459. }
  460. static int test_buf_select_pipe(void)
  461. {
  462. struct io_uring_sqe *sqe;
  463. struct io_uring_cqe *cqe;
  464. struct io_uring ring;
  465. int ret, i;
  466. int fds[2];
  467. if (no_buf_select)
  468. return 0;
  469. ret = io_uring_queue_init(64, &ring, 0);
  470. if (ret) {
  471. fprintf(stderr, "ring create failed: %d\n", ret);
  472. return 1;
  473. }
  474. ret = provide_buffers_iovec(&ring, 0);
  475. if (ret) {
  476. fprintf(stderr, "provide buffers failed: %d\n", ret);
  477. return 1;
  478. }
  479. ret = pipe(fds);
  480. if (ret) {
  481. fprintf(stderr, "pipe failed: %d\n", ret);
  482. return 1;
  483. }
  484. for (i = 0; i < 5; i++) {
  485. sqe = io_uring_get_sqe(&ring);
  486. io_uring_prep_read(sqe, fds[0], NULL, 1 /* max read 1 per go */, -1);
  487. sqe->flags |= IOSQE_BUFFER_SELECT;
  488. sqe->buf_group = 0;
  489. }
  490. io_uring_submit(&ring);
  491. ret = write(fds[1], "01234", 5);
  492. if (ret != 5) {
  493. fprintf(stderr, "pipe write failed %d\n", ret);
  494. return 1;
  495. }
  496. for (i = 0; i < 5; i++) {
  497. const char *buff;
  498. if (io_uring_wait_cqe(&ring, &cqe)) {
  499. fprintf(stderr, "bad wait %d\n", i);
  500. return 1;
  501. }
  502. if (cqe->res != 1) {
  503. fprintf(stderr, "expected read %d\n", cqe->res);
  504. return 1;
  505. }
  506. if (!(cqe->flags & IORING_CQE_F_BUFFER)) {
  507. fprintf(stderr, "no buffer %d\n", cqe->res);
  508. return 1;
  509. }
  510. buff = vecs[cqe->flags >> 16].iov_base;
  511. if (*buff != '0' + i) {
  512. fprintf(stderr, "%d: expected %c, got %c\n", i, '0' + i, *buff);
  513. return 1;
  514. }
  515. io_uring_cqe_seen(&ring, cqe);
  516. }
  517. close(fds[0]);
  518. close(fds[1]);
  519. io_uring_queue_exit(&ring);
  520. return 0;
  521. }
  522. static int test_buf_select(const char *filename, int nonvec)
  523. {
  524. struct io_uring_probe *p;
  525. struct io_uring ring;
  526. int ret, i;
  527. ret = io_uring_queue_init(64, &ring, 0);
  528. if (ret) {
  529. fprintf(stderr, "ring create failed: %d\n", ret);
  530. return 1;
  531. }
  532. p = io_uring_get_probe_ring(&ring);
  533. if (!p || !io_uring_opcode_supported(p, IORING_OP_PROVIDE_BUFFERS)) {
  534. no_buf_select = 1;
  535. fprintf(stdout, "Buffer select not supported, skipping\n");
  536. return 0;
  537. }
  538. io_uring_free_probe(p);
  539. /*
  540. * Write out data with known pattern
  541. */
  542. for (i = 0; i < BUFFERS; i++)
  543. memset(vecs[i].iov_base, i, vecs[i].iov_len);
  544. ret = __test_io(filename, &ring, 1, 0, 0, 0, 0, 0, 1, BS);
  545. if (ret) {
  546. fprintf(stderr, "failed writing data\n");
  547. return 1;
  548. }
  549. for (i = 0; i < BUFFERS; i++)
  550. memset(vecs[i].iov_base, 0x55, vecs[i].iov_len);
  551. ret = provide_buffers_iovec(&ring, 1);
  552. if (ret)
  553. return ret;
  554. ret = __test_io(filename, &ring, 0, 0, 0, 0, nonvec, 1, 1, BS);
  555. io_uring_queue_exit(&ring);
  556. return ret;
  557. }
  558. static int test_rem_buf(int batch, int sqe_flags)
  559. {
  560. struct io_uring_sqe *sqe;
  561. struct io_uring_cqe *cqe;
  562. struct io_uring ring;
  563. int left, ret, nr = 0;
  564. int bgid = 1;
  565. if (no_buf_select)
  566. return 0;
  567. ret = io_uring_queue_init(64, &ring, 0);
  568. if (ret) {
  569. fprintf(stderr, "ring create failed: %d\n", ret);
  570. return 1;
  571. }
  572. ret = provide_buffers_iovec(&ring, bgid);
  573. if (ret)
  574. return ret;
  575. left = BUFFERS;
  576. while (left) {
  577. int to_rem = (left < batch) ? left : batch;
  578. left -= to_rem;
  579. sqe = io_uring_get_sqe(&ring);
  580. io_uring_prep_remove_buffers(sqe, to_rem, bgid);
  581. sqe->user_data = to_rem;
  582. sqe->flags |= sqe_flags;
  583. ++nr;
  584. }
  585. ret = io_uring_submit(&ring);
  586. if (ret != nr) {
  587. fprintf(stderr, "submit: %d\n", ret);
  588. return -1;
  589. }
  590. for (; nr > 0; nr--) {
  591. ret = io_uring_wait_cqe(&ring, &cqe);
  592. if (ret) {
  593. fprintf(stderr, "wait_cqe=%d\n", ret);
  594. return 1;
  595. }
  596. if (cqe->res != cqe->user_data) {
  597. fprintf(stderr, "cqe->res=%d\n", cqe->res);
  598. return 1;
  599. }
  600. io_uring_cqe_seen(&ring, cqe);
  601. }
  602. io_uring_queue_exit(&ring);
  603. return ret;
  604. }
  605. static int test_rem_buf_single(int to_rem)
  606. {
  607. struct io_uring_sqe *sqe;
  608. struct io_uring_cqe *cqe;
  609. struct io_uring ring;
  610. int ret, expected;
  611. int bgid = 1;
  612. if (no_buf_select)
  613. return 0;
  614. ret = io_uring_queue_init(64, &ring, 0);
  615. if (ret) {
  616. fprintf(stderr, "ring create failed: %d\n", ret);
  617. return 1;
  618. }
  619. ret = provide_buffers_iovec(&ring, bgid);
  620. if (ret)
  621. return ret;
  622. expected = (to_rem > BUFFERS) ? BUFFERS : to_rem;
  623. sqe = io_uring_get_sqe(&ring);
  624. io_uring_prep_remove_buffers(sqe, to_rem, bgid);
  625. ret = io_uring_submit(&ring);
  626. if (ret != 1) {
  627. fprintf(stderr, "submit: %d\n", ret);
  628. return -1;
  629. }
  630. ret = io_uring_wait_cqe(&ring, &cqe);
  631. if (ret) {
  632. fprintf(stderr, "wait_cqe=%d\n", ret);
  633. return 1;
  634. }
  635. if (cqe->res != expected) {
  636. fprintf(stderr, "cqe->res=%d, expected=%d\n", cqe->res, expected);
  637. return 1;
  638. }
  639. io_uring_cqe_seen(&ring, cqe);
  640. io_uring_queue_exit(&ring);
  641. return ret;
  642. }
  643. static int test_io_link(const char *file)
  644. {
  645. const int nr_links = 100;
  646. const int link_len = 100;
  647. const int nr_sqes = nr_links * link_len;
  648. struct io_uring_sqe *sqe;
  649. struct io_uring_cqe *cqe;
  650. struct io_uring ring;
  651. int i, j, fd, ret;
  652. fd = open(file, O_WRONLY);
  653. if (fd < 0) {
  654. if (errno == EPERM || errno == EACCES)
  655. return 0;
  656. perror("file open");
  657. goto err;
  658. }
  659. ret = io_uring_queue_init(nr_sqes, &ring, 0);
  660. if (ret) {
  661. fprintf(stderr, "ring create failed: %d\n", ret);
  662. goto err;
  663. }
  664. for (i = 0; i < nr_links; ++i) {
  665. for (j = 0; j < link_len; ++j) {
  666. sqe = io_uring_get_sqe(&ring);
  667. if (!sqe) {
  668. fprintf(stderr, "sqe get failed\n");
  669. goto err;
  670. }
  671. io_uring_prep_writev(sqe, fd, &vecs[0], 1, 0);
  672. sqe->flags |= IOSQE_ASYNC;
  673. if (j != link_len - 1)
  674. sqe->flags |= IOSQE_IO_LINK;
  675. }
  676. }
  677. ret = io_uring_submit(&ring);
  678. if (ret != nr_sqes) {
  679. ret = io_uring_peek_cqe(&ring, &cqe);
  680. if (!ret && cqe->res == -EINVAL) {
  681. fprintf(stdout, "IOSQE_ASYNC not supported, skipped\n");
  682. goto out;
  683. }
  684. fprintf(stderr, "submit got %d, wanted %d\n", ret, nr_sqes);
  685. goto err;
  686. }
  687. for (i = 0; i < nr_sqes; i++) {
  688. ret = io_uring_wait_cqe(&ring, &cqe);
  689. if (ret) {
  690. fprintf(stderr, "wait_cqe=%d\n", ret);
  691. goto err;
  692. }
  693. if (cqe->res == -EINVAL) {
  694. if (!warned) {
  695. fprintf(stdout, "Non-vectored IO not "
  696. "supported, skipping\n");
  697. warned = 1;
  698. no_read = 1;
  699. }
  700. } else if (cqe->res != BS) {
  701. fprintf(stderr, "cqe res %d, wanted %d\n", cqe->res, BS);
  702. goto err;
  703. }
  704. io_uring_cqe_seen(&ring, cqe);
  705. }
  706. out:
  707. io_uring_queue_exit(&ring);
  708. close(fd);
  709. return 0;
  710. err:
  711. if (fd != -1)
  712. close(fd);
  713. return 1;
  714. }
  715. static int test_write_efbig(void)
  716. {
  717. struct io_uring_sqe *sqe;
  718. struct io_uring_cqe *cqe;
  719. struct io_uring ring;
  720. struct rlimit rlim, old_rlim;
  721. int i, fd, ret;
  722. loff_t off;
  723. if (geteuid()) {
  724. fprintf(stdout, "Not root, skipping %s\n", __FUNCTION__);
  725. return 0;
  726. }
  727. if (getrlimit(RLIMIT_FSIZE, &old_rlim) < 0) {
  728. perror("getrlimit");
  729. return 1;
  730. }
  731. rlim = old_rlim;
  732. rlim.rlim_cur = 128 * 1024;
  733. rlim.rlim_max = 128 * 1024;
  734. if (setrlimit(RLIMIT_FSIZE, &rlim) < 0) {
  735. perror("setrlimit");
  736. return 1;
  737. }
  738. fd = open(".efbig", O_WRONLY | O_CREAT, 0644);
  739. if (fd < 0) {
  740. perror("file open");
  741. goto err;
  742. }
  743. unlink(".efbig");
  744. ret = io_uring_queue_init(32, &ring, 0);
  745. if (ret) {
  746. fprintf(stderr, "ring create failed: %d\n", ret);
  747. goto err;
  748. }
  749. off = 0;
  750. for (i = 0; i < 32; i++) {
  751. sqe = io_uring_get_sqe(&ring);
  752. if (!sqe) {
  753. fprintf(stderr, "sqe get failed\n");
  754. goto err;
  755. }
  756. io_uring_prep_writev(sqe, fd, &vecs[i], 1, off);
  757. io_uring_sqe_set_data64(sqe, i);
  758. off += BS;
  759. }
  760. ret = io_uring_submit(&ring);
  761. if (ret != 32) {
  762. fprintf(stderr, "submit got %d, wanted %d\n", ret, 32);
  763. goto err;
  764. }
  765. for (i = 0; i < 32; i++) {
  766. ret = io_uring_wait_cqe(&ring, &cqe);
  767. if (ret) {
  768. fprintf(stderr, "wait_cqe=%d\n", ret);
  769. goto err;
  770. }
  771. if (cqe->user_data < 16) {
  772. if (cqe->res != BS) {
  773. fprintf(stderr, "bad write: %d\n", cqe->res);
  774. goto err;
  775. }
  776. } else {
  777. if (cqe->res != -EFBIG) {
  778. fprintf(stderr, "Expected -EFBIG: %d\n", cqe->res);
  779. goto err;
  780. }
  781. }
  782. io_uring_cqe_seen(&ring, cqe);
  783. }
  784. io_uring_queue_exit(&ring);
  785. close(fd);
  786. unlink(".efbig");
  787. if (setrlimit(RLIMIT_FSIZE, &old_rlim) < 0) {
  788. perror("setrlimit");
  789. return 1;
  790. }
  791. return 0;
  792. err:
  793. if (fd != -1)
  794. close(fd);
  795. return 1;
  796. }
  797. int main(int argc, char *argv[])
  798. {
  799. int i, ret, nr;
  800. char buf[256];
  801. char *fname;
  802. if (argc > 1) {
  803. fname = argv[1];
  804. } else {
  805. srand((unsigned)time(NULL));
  806. snprintf(buf, sizeof(buf), ".basic-rw-%u-%u",
  807. (unsigned)rand(), (unsigned)getpid());
  808. fname = buf;
  809. t_create_file(fname, FILE_SIZE);
  810. }
  811. signal(SIGXFSZ, SIG_IGN);
  812. vecs = t_create_buffers(BUFFERS, BS);
  813. /* if we don't have nonvec read, skip testing that */
  814. nr = has_nonvec_read() ? 32 : 16;
  815. for (i = 0; i < nr; i++) {
  816. int write = (i & 1) != 0;
  817. int buffered = (i & 2) != 0;
  818. int sqthread = (i & 4) != 0;
  819. int fixed = (i & 8) != 0;
  820. int nonvec = (i & 16) != 0;
  821. ret = test_io(fname, write, buffered, sqthread, fixed, nonvec,
  822. BS);
  823. if (ret) {
  824. fprintf(stderr, "test_io failed %d/%d/%d/%d/%d\n",
  825. write, buffered, sqthread, fixed, nonvec);
  826. goto err;
  827. }
  828. }
  829. ret = test_buf_select(fname, 1);
  830. if (ret) {
  831. fprintf(stderr, "test_buf_select nonvec failed\n");
  832. goto err;
  833. }
  834. ret = test_buf_select(fname, 0);
  835. if (ret) {
  836. fprintf(stderr, "test_buf_select vec failed\n");
  837. goto err;
  838. }
  839. ret = test_buf_select_short(fname, 1);
  840. if (ret) {
  841. fprintf(stderr, "test_buf_select_short nonvec failed\n");
  842. goto err;
  843. }
  844. ret = test_buf_select_short(fname, 0);
  845. if (ret) {
  846. fprintf(stderr, "test_buf_select_short vec failed\n");
  847. goto err;
  848. }
  849. ret = test_buf_select_pipe();
  850. if (ret) {
  851. fprintf(stderr, "test_buf_select_pipe failed\n");
  852. goto err;
  853. }
  854. ret = test_eventfd_read();
  855. if (ret) {
  856. fprintf(stderr, "test_eventfd_read failed\n");
  857. goto err;
  858. }
  859. ret = read_poll_link(fname);
  860. if (ret == T_EXIT_FAIL) {
  861. fprintf(stderr, "read_poll_link failed\n");
  862. goto err;
  863. }
  864. ret = test_io_link(fname);
  865. if (ret) {
  866. fprintf(stderr, "test_io_link failed\n");
  867. goto err;
  868. }
  869. ret = test_write_efbig();
  870. if (ret) {
  871. fprintf(stderr, "test_write_efbig failed\n");
  872. goto err;
  873. }
  874. ret = test_rem_buf(1, 0);
  875. if (ret) {
  876. fprintf(stderr, "test_rem_buf by 1 failed\n");
  877. goto err;
  878. }
  879. ret = test_rem_buf(10, 0);
  880. if (ret) {
  881. fprintf(stderr, "test_rem_buf by 10 failed\n");
  882. goto err;
  883. }
  884. ret = test_rem_buf(2, IOSQE_IO_LINK);
  885. if (ret) {
  886. fprintf(stderr, "test_rem_buf link failed\n");
  887. goto err;
  888. }
  889. ret = test_rem_buf(2, IOSQE_ASYNC);
  890. if (ret) {
  891. fprintf(stderr, "test_rem_buf async failed\n");
  892. goto err;
  893. }
  894. if(vecs != NULL) {
  895. for (i = 0; i < BUFFERS; i++)
  896. free(vecs[i].iov_base);
  897. }
  898. free(vecs);
  899. srand((unsigned)time(NULL));
  900. if (create_nonaligned_buffers()) {
  901. fprintf(stderr, "file creation failed\n");
  902. goto err;
  903. }
  904. /* test fixed bufs with non-aligned len/offset */
  905. for (i = 0; i < nr; i++) {
  906. int write = (i & 1) != 0;
  907. int buffered = (i & 2) != 0;
  908. int sqthread = (i & 4) != 0;
  909. int fixed = (i & 8) != 0;
  910. int nonvec = (i & 16) != 0;
  911. /* direct IO requires alignment, skip it */
  912. if (!buffered || !fixed || nonvec)
  913. continue;
  914. ret = test_io(fname, write, buffered, sqthread, fixed, nonvec,
  915. -1);
  916. if (ret) {
  917. fprintf(stderr, "test_io failed %d/%d/%d/%d/%d\n",
  918. write, buffered, sqthread, fixed, nonvec);
  919. goto err;
  920. }
  921. }
  922. ret = test_rem_buf_single(BUFFERS + 1);
  923. if (ret) {
  924. fprintf(stderr, "test_rem_buf_single(BUFFERS + 1) failed\n");
  925. goto err;
  926. }
  927. if (fname != argv[1])
  928. unlink(fname);
  929. return 0;
  930. err:
  931. if (fname != argv[1])
  932. unlink(fname);
  933. return 1;
  934. }