1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) International Business Machines Corp., 2003 4f08c3bdfSopenharmony_ci * Copyright (c) Linux Test Project, 2004-2019 5f08c3bdfSopenharmony_ci * 6f08c3bdfSopenharmony_ci * AUTHORS 7f08c3bdfSopenharmony_ci * Kai Zhao (ltcd3@cn.ibm.com) 8f08c3bdfSopenharmony_ci */ 9f08c3bdfSopenharmony_ci 10f08c3bdfSopenharmony_ci#include "config.h" 11f08c3bdfSopenharmony_ci#include "tst_test.h" 12f08c3bdfSopenharmony_ci 13f08c3bdfSopenharmony_ci#ifdef HAVE_LIBAIO 14f08c3bdfSopenharmony_ci#include <errno.h> 15f08c3bdfSopenharmony_ci#include <stdlib.h> 16f08c3bdfSopenharmony_ci#include <libaio.h> 17f08c3bdfSopenharmony_ci 18f08c3bdfSopenharmony_ci#define AIO_MAXIO 32 19f08c3bdfSopenharmony_ci#define AIO_BLKSIZE (64*1024) 20f08c3bdfSopenharmony_ci 21f08c3bdfSopenharmony_cistatic int wait_count; 22f08c3bdfSopenharmony_ci 23f08c3bdfSopenharmony_ci#define DESC_FLAGS_OPR(x, y) .desc = (x == IO_CMD_PWRITE ? "WRITE: " #y: "READ : " #y), \ 24f08c3bdfSopenharmony_ci .flags = y, .operation = x 25f08c3bdfSopenharmony_ci 26f08c3bdfSopenharmony_cistruct testcase { 27f08c3bdfSopenharmony_ci const char *desc; 28f08c3bdfSopenharmony_ci int flags; 29f08c3bdfSopenharmony_ci int operation; 30f08c3bdfSopenharmony_ci} testcases[] = { 31f08c3bdfSopenharmony_ci { 32f08c3bdfSopenharmony_ci DESC_FLAGS_OPR(IO_CMD_PWRITE, O_WRONLY | O_TRUNC | O_DIRECT | O_LARGEFILE | O_CREAT), 33f08c3bdfSopenharmony_ci }, 34f08c3bdfSopenharmony_ci { 35f08c3bdfSopenharmony_ci DESC_FLAGS_OPR(IO_CMD_PREAD, O_RDONLY | O_DIRECT | O_LARGEFILE), 36f08c3bdfSopenharmony_ci }, 37f08c3bdfSopenharmony_ci { 38f08c3bdfSopenharmony_ci DESC_FLAGS_OPR(IO_CMD_PWRITE, O_RDWR | O_TRUNC), 39f08c3bdfSopenharmony_ci }, 40f08c3bdfSopenharmony_ci { 41f08c3bdfSopenharmony_ci DESC_FLAGS_OPR(IO_CMD_PREAD, O_RDWR), 42f08c3bdfSopenharmony_ci }, 43f08c3bdfSopenharmony_ci { 44f08c3bdfSopenharmony_ci DESC_FLAGS_OPR(IO_CMD_PWRITE, O_WRONLY | O_TRUNC), 45f08c3bdfSopenharmony_ci }, 46f08c3bdfSopenharmony_ci { 47f08c3bdfSopenharmony_ci DESC_FLAGS_OPR(IO_CMD_PREAD, O_RDONLY), 48f08c3bdfSopenharmony_ci }, 49f08c3bdfSopenharmony_ci}; 50f08c3bdfSopenharmony_ci 51f08c3bdfSopenharmony_ci/* 52f08c3bdfSopenharmony_ci * Fatal error handler 53f08c3bdfSopenharmony_ci */ 54f08c3bdfSopenharmony_cistatic void io_error(const char *func, int rc) 55f08c3bdfSopenharmony_ci{ 56f08c3bdfSopenharmony_ci if (rc == -ENOSYS) 57f08c3bdfSopenharmony_ci tst_brk(TCONF, "AIO not in this kernel"); 58f08c3bdfSopenharmony_ci else if (rc < 0) 59f08c3bdfSopenharmony_ci tst_brk(TFAIL, "%s: %s", func, strerror(-rc)); 60f08c3bdfSopenharmony_ci else 61f08c3bdfSopenharmony_ci tst_brk(TFAIL, "%s: error %d", func, rc); 62f08c3bdfSopenharmony_ci} 63f08c3bdfSopenharmony_ci 64f08c3bdfSopenharmony_ci/* 65f08c3bdfSopenharmony_ci * write work done 66f08c3bdfSopenharmony_ci */ 67f08c3bdfSopenharmony_cistatic void work_done(io_context_t ctx, struct iocb *iocb, long res, long res2) 68f08c3bdfSopenharmony_ci{ 69f08c3bdfSopenharmony_ci (void) ctx; // silence compiler warning (-Wunused) 70f08c3bdfSopenharmony_ci 71f08c3bdfSopenharmony_ci if (res2 != 0) 72f08c3bdfSopenharmony_ci io_error("aio write", res2); 73f08c3bdfSopenharmony_ci 74f08c3bdfSopenharmony_ci if (res != (long)iocb->u.c.nbytes) 75f08c3bdfSopenharmony_ci tst_brk(TFAIL, "write missed bytes expect %lu got %ld", 76f08c3bdfSopenharmony_ci iocb->u.c.nbytes, res); 77f08c3bdfSopenharmony_ci 78f08c3bdfSopenharmony_ci wait_count--; 79f08c3bdfSopenharmony_ci} 80f08c3bdfSopenharmony_ci 81f08c3bdfSopenharmony_ci/* 82f08c3bdfSopenharmony_ci * io_wait_run() - wait for an io_event and then call the callback. 83f08c3bdfSopenharmony_ci */ 84f08c3bdfSopenharmony_cistatic int io_wait_run(io_context_t ctx, struct timespec *to) 85f08c3bdfSopenharmony_ci{ 86f08c3bdfSopenharmony_ci struct io_event events[AIO_MAXIO]; 87f08c3bdfSopenharmony_ci struct io_event *ep; 88f08c3bdfSopenharmony_ci int ret, n; 89f08c3bdfSopenharmony_ci 90f08c3bdfSopenharmony_ci /* 91f08c3bdfSopenharmony_ci * get up to aio_maxio events at a time. 92f08c3bdfSopenharmony_ci */ 93f08c3bdfSopenharmony_ci ret = n = io_getevents(ctx, 1, AIO_MAXIO, events, to); 94f08c3bdfSopenharmony_ci 95f08c3bdfSopenharmony_ci /* 96f08c3bdfSopenharmony_ci * Call the callback functions for each event. 97f08c3bdfSopenharmony_ci */ 98f08c3bdfSopenharmony_ci for (ep = events; n-- > 0; ep++) { 99f08c3bdfSopenharmony_ci io_callback_t cb = (io_callback_t) ep->data; 100f08c3bdfSopenharmony_ci struct iocb *iocb = ep->obj; 101f08c3bdfSopenharmony_ci cb(ctx, iocb, ep->res, ep->res2); 102f08c3bdfSopenharmony_ci } 103f08c3bdfSopenharmony_ci return ret; 104f08c3bdfSopenharmony_ci} 105f08c3bdfSopenharmony_ci 106f08c3bdfSopenharmony_cistatic int io_tio(char *pathname, int flag, int operation) 107f08c3bdfSopenharmony_ci{ 108f08c3bdfSopenharmony_ci int res, fd = 0, i = 0; 109f08c3bdfSopenharmony_ci void *bufptr = NULL; 110f08c3bdfSopenharmony_ci off_t offset = 0; 111f08c3bdfSopenharmony_ci struct timespec timeout; 112f08c3bdfSopenharmony_ci struct stat fi_stat; 113f08c3bdfSopenharmony_ci size_t alignment; 114f08c3bdfSopenharmony_ci 115f08c3bdfSopenharmony_ci io_context_t myctx; 116f08c3bdfSopenharmony_ci struct iocb iocb_array[AIO_MAXIO]; 117f08c3bdfSopenharmony_ci struct iocb *iocbps[AIO_MAXIO]; 118f08c3bdfSopenharmony_ci 119f08c3bdfSopenharmony_ci fd = SAFE_OPEN(pathname, flag, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 120f08c3bdfSopenharmony_ci 121f08c3bdfSopenharmony_ci /* determine the alignment from the blksize of the underlying device */ 122f08c3bdfSopenharmony_ci SAFE_FSTAT(fd, &fi_stat); 123f08c3bdfSopenharmony_ci alignment = fi_stat.st_blksize; 124f08c3bdfSopenharmony_ci 125f08c3bdfSopenharmony_ci res = io_queue_init(AIO_MAXIO, &myctx); 126f08c3bdfSopenharmony_ci 127f08c3bdfSopenharmony_ci for (i = 0; i < AIO_MAXIO; i++) { 128f08c3bdfSopenharmony_ci 129f08c3bdfSopenharmony_ci switch (operation) { 130f08c3bdfSopenharmony_ci case IO_CMD_PWRITE: 131f08c3bdfSopenharmony_ci if (posix_memalign(&bufptr, alignment, AIO_BLKSIZE)) { 132f08c3bdfSopenharmony_ci tst_brk(TBROK | TERRNO, "posix_memalign failed"); 133f08c3bdfSopenharmony_ci return -1; 134f08c3bdfSopenharmony_ci } 135f08c3bdfSopenharmony_ci memset(bufptr, 0, AIO_BLKSIZE); 136f08c3bdfSopenharmony_ci 137f08c3bdfSopenharmony_ci io_prep_pwrite(&iocb_array[i], fd, bufptr, 138f08c3bdfSopenharmony_ci AIO_BLKSIZE, offset); 139f08c3bdfSopenharmony_ci io_set_callback(&iocb_array[i], work_done); 140f08c3bdfSopenharmony_ci iocbps[i] = &iocb_array[i]; 141f08c3bdfSopenharmony_ci offset += AIO_BLKSIZE; 142f08c3bdfSopenharmony_ci 143f08c3bdfSopenharmony_ci break; 144f08c3bdfSopenharmony_ci case IO_CMD_PREAD: 145f08c3bdfSopenharmony_ci if (posix_memalign(&bufptr, alignment, AIO_BLKSIZE)) { 146f08c3bdfSopenharmony_ci tst_brk(TBROK | TERRNO, "posix_memalign failed"); 147f08c3bdfSopenharmony_ci return -1; 148f08c3bdfSopenharmony_ci } 149f08c3bdfSopenharmony_ci memset(bufptr, 0, AIO_BLKSIZE); 150f08c3bdfSopenharmony_ci 151f08c3bdfSopenharmony_ci io_prep_pread(&iocb_array[i], fd, bufptr, 152f08c3bdfSopenharmony_ci AIO_BLKSIZE, offset); 153f08c3bdfSopenharmony_ci io_set_callback(&iocb_array[i], work_done); 154f08c3bdfSopenharmony_ci iocbps[i] = &iocb_array[i]; 155f08c3bdfSopenharmony_ci offset += AIO_BLKSIZE; 156f08c3bdfSopenharmony_ci break; 157f08c3bdfSopenharmony_ci default: 158f08c3bdfSopenharmony_ci tst_res(TFAIL, "Command failed; opcode returned: %d", operation); 159f08c3bdfSopenharmony_ci return -1; 160f08c3bdfSopenharmony_ci break; 161f08c3bdfSopenharmony_ci } 162f08c3bdfSopenharmony_ci } 163f08c3bdfSopenharmony_ci 164f08c3bdfSopenharmony_ci do { 165f08c3bdfSopenharmony_ci res = io_submit(myctx, AIO_MAXIO, iocbps); 166f08c3bdfSopenharmony_ci } while (res == -EAGAIN); 167f08c3bdfSopenharmony_ci 168f08c3bdfSopenharmony_ci if (res < 0) 169f08c3bdfSopenharmony_ci io_error("io_submit tio", res); 170f08c3bdfSopenharmony_ci 171f08c3bdfSopenharmony_ci /* 172f08c3bdfSopenharmony_ci * We have submitted all the i/o requests. Wait for them to complete and 173f08c3bdfSopenharmony_ci * call the callbacks. 174f08c3bdfSopenharmony_ci */ 175f08c3bdfSopenharmony_ci wait_count = AIO_MAXIO; 176f08c3bdfSopenharmony_ci 177f08c3bdfSopenharmony_ci timeout.tv_sec = 30; 178f08c3bdfSopenharmony_ci timeout.tv_nsec = 0; 179f08c3bdfSopenharmony_ci 180f08c3bdfSopenharmony_ci switch (operation) { 181f08c3bdfSopenharmony_ci case IO_CMD_PREAD: 182f08c3bdfSopenharmony_ci case IO_CMD_PWRITE: 183f08c3bdfSopenharmony_ci { 184f08c3bdfSopenharmony_ci while (wait_count) { 185f08c3bdfSopenharmony_ci res = io_wait_run(myctx, &timeout); 186f08c3bdfSopenharmony_ci if (res < 0) 187f08c3bdfSopenharmony_ci io_error("io_wait_run", res); 188f08c3bdfSopenharmony_ci } 189f08c3bdfSopenharmony_ci } 190f08c3bdfSopenharmony_ci break; 191f08c3bdfSopenharmony_ci } 192f08c3bdfSopenharmony_ci 193f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 194f08c3bdfSopenharmony_ci 195f08c3bdfSopenharmony_ci for (i = 0; i < AIO_MAXIO; i++) 196f08c3bdfSopenharmony_ci if (iocb_array[i].u.c.buf != NULL) 197f08c3bdfSopenharmony_ci free(iocb_array[i].u.c.buf); 198f08c3bdfSopenharmony_ci 199f08c3bdfSopenharmony_ci io_queue_release(myctx); 200f08c3bdfSopenharmony_ci 201f08c3bdfSopenharmony_ci return 0; 202f08c3bdfSopenharmony_ci} 203f08c3bdfSopenharmony_ci 204f08c3bdfSopenharmony_cistatic void test_io(unsigned int n) 205f08c3bdfSopenharmony_ci{ 206f08c3bdfSopenharmony_ci int status, new_flags; 207f08c3bdfSopenharmony_ci struct testcase *tc = testcases + n; 208f08c3bdfSopenharmony_ci 209f08c3bdfSopenharmony_ci new_flags = tc->flags; 210f08c3bdfSopenharmony_ci 211f08c3bdfSopenharmony_ci if ((tst_fs_type(".") == TST_TMPFS_MAGIC) && (tc->flags & O_DIRECT)) { 212f08c3bdfSopenharmony_ci tst_res(TINFO, "Drop O_DIRECT flag for tmpfs"); 213f08c3bdfSopenharmony_ci new_flags &= ~O_DIRECT; 214f08c3bdfSopenharmony_ci } 215f08c3bdfSopenharmony_ci 216f08c3bdfSopenharmony_ci status = io_tio("file", new_flags, tc->operation); 217f08c3bdfSopenharmony_ci if (status) 218f08c3bdfSopenharmony_ci tst_res(TFAIL, "%s, status = %d", tc->desc, status); 219f08c3bdfSopenharmony_ci else 220f08c3bdfSopenharmony_ci tst_res(TPASS, "%s", tc->desc); 221f08c3bdfSopenharmony_ci} 222f08c3bdfSopenharmony_ci 223f08c3bdfSopenharmony_cistatic struct tst_test test = { 224f08c3bdfSopenharmony_ci .needs_tmpdir = 1, 225f08c3bdfSopenharmony_ci .test = test_io, 226f08c3bdfSopenharmony_ci .tcnt = ARRAY_SIZE(testcases), 227f08c3bdfSopenharmony_ci}; 228f08c3bdfSopenharmony_ci 229f08c3bdfSopenharmony_ci#else 230f08c3bdfSopenharmony_ciTST_TEST_TCONF("test requires libaio and its development packages"); 231f08c3bdfSopenharmony_ci#endif 232