1f44eb013SEnji Cooper /*- 2f44eb013SEnji Cooper * Copyright (C) 2005 IronPort Systems, Inc. All rights reserved. 3f44eb013SEnji Cooper * 4f44eb013SEnji Cooper * Redistribution and use in source and binary forms, with or without 5f44eb013SEnji Cooper * modification, are permitted provided that the following conditions 6f44eb013SEnji Cooper * are met: 7f44eb013SEnji Cooper * 1. Redistributions of source code must retain the above copyright 8f44eb013SEnji Cooper * notice, this list of conditions and the following disclaimer. 9f44eb013SEnji Cooper * 2. Redistributions in binary form must reproduce the above copyright 10f44eb013SEnji Cooper * notice, this list of conditions and the following disclaimer in the 11f44eb013SEnji Cooper * documentation and/or other materials provided with the distribution. 12f44eb013SEnji Cooper * 13f44eb013SEnji Cooper * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14f44eb013SEnji Cooper * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15f44eb013SEnji Cooper * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16f44eb013SEnji Cooper * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17f44eb013SEnji Cooper * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18f44eb013SEnji Cooper * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19f44eb013SEnji Cooper * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20f44eb013SEnji Cooper * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21f44eb013SEnji Cooper * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22f44eb013SEnji Cooper * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23f44eb013SEnji Cooper * SUCH DAMAGE. 24f44eb013SEnji Cooper */ 25f44eb013SEnji Cooper 26f44eb013SEnji Cooper /* 27f44eb013SEnji Cooper * Prerequisities: 28f44eb013SEnji Cooper * - AIO support must be compiled into the kernel (see sys/<arch>/NOTES for 29f44eb013SEnji Cooper * more details). 30f44eb013SEnji Cooper * 31f44eb013SEnji Cooper * Note: it is a good idea to run this against a physical drive to 32f44eb013SEnji Cooper * exercise the physio fast path (ie. aio_kqueue /dev/<something safe>) 33f44eb013SEnji Cooper */ 34f44eb013SEnji Cooper 35f44eb013SEnji Cooper #include <sys/types.h> 36f44eb013SEnji Cooper #include <sys/event.h> 37f44eb013SEnji Cooper #include <sys/time.h> 38*7c94d515SDavid Bright #include <assert.h> 39f44eb013SEnji Cooper #include <aio.h> 40f44eb013SEnji Cooper #include <err.h> 41f44eb013SEnji Cooper #include <errno.h> 42f44eb013SEnji Cooper #include <fcntl.h> 43f44eb013SEnji Cooper #include <stdlib.h> 44f44eb013SEnji Cooper #include <stdio.h> 45f44eb013SEnji Cooper #include <string.h> 46f44eb013SEnji Cooper #include <unistd.h> 47f44eb013SEnji Cooper 484e5f38d6SEnji Cooper #include "freebsd_test_suite/macros.h" 49f3215338SJohn Baldwin #include "local.h" 50f44eb013SEnji Cooper 514e5f38d6SEnji Cooper #define PATH_TEMPLATE "aio.XXXXXXXXXX" 524e5f38d6SEnji Cooper 53f44eb013SEnji Cooper #define MAX_RUNS 300 54f44eb013SEnji Cooper /* #define DEBUG */ 55f44eb013SEnji Cooper 56f44eb013SEnji Cooper int 57f44eb013SEnji Cooper main (int argc, char *argv[]) 58f44eb013SEnji Cooper { 59c52ef9bbSAlan Somers struct aiocb **iocb, *kq_iocb; 604e5f38d6SEnji Cooper char *file, pathname[sizeof(PATH_TEMPLATE)+1]; 61f10dd8afSAlan Somers struct kevent kq_returned; 62f44eb013SEnji Cooper struct timespec ts; 634e5f38d6SEnji Cooper char buffer[32768]; 64c52ef9bbSAlan Somers int max_queue_per_proc; 65c52ef9bbSAlan Somers size_t max_queue_per_proc_size; 66e26e73f3SEnji Cooper #ifdef DEBUG 67e26e73f3SEnji Cooper int cancel, error; 68e26e73f3SEnji Cooper #endif 69e26e73f3SEnji Cooper int failed = 0, fd, kq, pending, result, run; 704e5f38d6SEnji Cooper int tmp_file = 0; 71c52ef9bbSAlan Somers int i, j; 72f44eb013SEnji Cooper 734e5f38d6SEnji Cooper PLAIN_REQUIRE_KERNEL_MODULE("aio", 0); 74f3215338SJohn Baldwin PLAIN_REQUIRE_UNSAFE_AIO(0); 754e5f38d6SEnji Cooper 76c52ef9bbSAlan Somers max_queue_per_proc_size = sizeof(max_queue_per_proc); 77c52ef9bbSAlan Somers if (sysctlbyname("vfs.aio.max_aio_queue_per_proc", 78c52ef9bbSAlan Somers &max_queue_per_proc, &max_queue_per_proc_size, NULL, 0) != 0) 79c52ef9bbSAlan Somers err(1, "sysctlbyname"); 80c52ef9bbSAlan Somers iocb = calloc(max_queue_per_proc, sizeof(struct aiocb*)); 81c52ef9bbSAlan Somers if (iocb == NULL) 82c52ef9bbSAlan Somers err(1, "calloc"); 83c52ef9bbSAlan Somers 844e5f38d6SEnji Cooper kq = kqueue(); 85f44eb013SEnji Cooper if (kq < 0) { 86f44eb013SEnji Cooper perror("No kqeueue\n"); 87f44eb013SEnji Cooper exit(1); 88f44eb013SEnji Cooper } 89f44eb013SEnji Cooper 90f44eb013SEnji Cooper if (argc == 1) { 91f44eb013SEnji Cooper strcpy(pathname, PATH_TEMPLATE); 92f44eb013SEnji Cooper fd = mkstemp(pathname); 93f44eb013SEnji Cooper file = pathname; 94f44eb013SEnji Cooper tmp_file = 1; 95f44eb013SEnji Cooper } else { 96f44eb013SEnji Cooper file = argv[1]; 97f44eb013SEnji Cooper fd = open(file, O_RDWR|O_CREAT, 0666); 98f44eb013SEnji Cooper } 99f44eb013SEnji Cooper if (fd == -1) 100f44eb013SEnji Cooper err(1, "Can't open %s\n", file); 101f44eb013SEnji Cooper 102f44eb013SEnji Cooper for (run = 0; run < MAX_RUNS; run++){ 103f44eb013SEnji Cooper #ifdef DEBUG 104f44eb013SEnji Cooper printf("Run %d\n", run); 105f44eb013SEnji Cooper #endif 106c52ef9bbSAlan Somers for (i = 0; i < max_queue_per_proc; i++) { 107f44eb013SEnji Cooper iocb[i] = (struct aiocb *)calloc(1, 108f44eb013SEnji Cooper sizeof(struct aiocb)); 109f44eb013SEnji Cooper if (iocb[i] == NULL) 110f44eb013SEnji Cooper err(1, "calloc"); 111f44eb013SEnji Cooper } 112f44eb013SEnji Cooper 113f44eb013SEnji Cooper pending = 0; 114c52ef9bbSAlan Somers for (i = 0; i < max_queue_per_proc; i++) { 115f44eb013SEnji Cooper pending++; 116f44eb013SEnji Cooper iocb[i]->aio_nbytes = sizeof(buffer); 117f44eb013SEnji Cooper iocb[i]->aio_buf = buffer; 118f44eb013SEnji Cooper iocb[i]->aio_fildes = fd; 119f44eb013SEnji Cooper iocb[i]->aio_offset = iocb[i]->aio_nbytes * i * run; 120f44eb013SEnji Cooper 121f44eb013SEnji Cooper iocb[i]->aio_sigevent.sigev_notify_kqueue = kq; 122f44eb013SEnji Cooper iocb[i]->aio_sigevent.sigev_value.sival_ptr = iocb[i]; 123f44eb013SEnji Cooper iocb[i]->aio_sigevent.sigev_notify = SIGEV_KEVENT; 124f44eb013SEnji Cooper 125f44eb013SEnji Cooper result = aio_write(iocb[i]); 126f44eb013SEnji Cooper if (result != 0) { 127f44eb013SEnji Cooper perror("aio_write"); 128f44eb013SEnji Cooper printf("Result %d iteration %d\n", result, i); 129f44eb013SEnji Cooper exit(1); 130f44eb013SEnji Cooper } 131f44eb013SEnji Cooper #ifdef DEBUG 132f44eb013SEnji Cooper printf("WRITE %d is at %p\n", i, iocb[i]); 133f44eb013SEnji Cooper #endif 134f44eb013SEnji Cooper result = rand(); 135f44eb013SEnji Cooper if (result < RAND_MAX/32) { 136f44eb013SEnji Cooper if (result > RAND_MAX/64) { 137f44eb013SEnji Cooper result = aio_cancel(fd, iocb[i]); 138f44eb013SEnji Cooper #ifdef DEBUG 139f44eb013SEnji Cooper printf("Cancel %d %p result %d\n", i, iocb[i], result); 140f44eb013SEnji Cooper #endif 141f44eb013SEnji Cooper if (result == AIO_CANCELED) { 142f44eb013SEnji Cooper aio_return(iocb[i]); 143f44eb013SEnji Cooper iocb[i] = NULL; 144f44eb013SEnji Cooper pending--; 145f44eb013SEnji Cooper } 146f44eb013SEnji Cooper } 147f44eb013SEnji Cooper } 148f44eb013SEnji Cooper } 149e26e73f3SEnji Cooper #ifdef DEBUG 150c52ef9bbSAlan Somers cancel = max_queue_per_proc - pending; 151e26e73f3SEnji Cooper #endif 152f44eb013SEnji Cooper 153f44eb013SEnji Cooper i = 0; 154f44eb013SEnji Cooper while (pending) { 155f44eb013SEnji Cooper 156f44eb013SEnji Cooper for (;;) { 157f44eb013SEnji Cooper 158f10dd8afSAlan Somers bzero(&kq_returned, sizeof(kq_returned)); 159f44eb013SEnji Cooper ts.tv_sec = 0; 160f44eb013SEnji Cooper ts.tv_nsec = 1; 161f44eb013SEnji Cooper result = kevent(kq, NULL, 0, 162f44eb013SEnji Cooper &kq_returned, 1, &ts); 163e26e73f3SEnji Cooper #ifdef DEBUG 164f44eb013SEnji Cooper error = errno; 165e26e73f3SEnji Cooper #endif 166f44eb013SEnji Cooper if (result < 0) 167f44eb013SEnji Cooper perror("kevent error: "); 168f44eb013SEnji Cooper kq_iocb = kq_returned.udata; 169f44eb013SEnji Cooper #ifdef DEBUG 170f44eb013SEnji Cooper printf("kevent %d %d errno %d return.ident %p " 171c189c73fSAlan Somers "return.data %p return.udata %p %p" 172c189c73fSAlan Somers " filter %d flags %#x fflags %#x\n", 173f44eb013SEnji Cooper i, result, error, 17495c91f3bSAlan Somers (void*)kq_returned.ident, 17595c91f3bSAlan Somers (void*)kq_returned.data, 176f44eb013SEnji Cooper kq_returned.udata, 177c189c73fSAlan Somers kq_iocb, 178c189c73fSAlan Somers kq_returned.filter, 179c189c73fSAlan Somers kq_returned.flags, 180c189c73fSAlan Somers kq_returned.fflags); 181c189c73fSAlan Somers if (result > 0) 182c189c73fSAlan Somers printf("\tsigev_notify_kevent_flags %#x\n", 183c189c73fSAlan Somers ((struct aiocb*)(kq_returned.ident))->aio_sigevent.sigev_notify_kevent_flags); 184f44eb013SEnji Cooper #endif 185f44eb013SEnji Cooper 186f44eb013SEnji Cooper if (kq_iocb) 187f44eb013SEnji Cooper break; 188f44eb013SEnji Cooper #ifdef DEBUG 189c189c73fSAlan Somers printf("Try again left %d out of %d %d\n", 190c52ef9bbSAlan Somers pending, max_queue_per_proc, cancel); 191f44eb013SEnji Cooper #endif 192f44eb013SEnji Cooper } 193f44eb013SEnji Cooper 194c52ef9bbSAlan Somers for (j = 0; j < max_queue_per_proc && iocb[j] != kq_iocb; 195f44eb013SEnji Cooper j++) ; 196*7c94d515SDavid Bright assert(j < max_queue_per_proc); 197f44eb013SEnji Cooper #ifdef DEBUG 198f44eb013SEnji Cooper printf("kq_iocb %p\n", kq_iocb); 199f44eb013SEnji Cooper 200f44eb013SEnji Cooper printf("Error Result for %d is %d pending %d\n", 201f44eb013SEnji Cooper j, result, pending); 202f44eb013SEnji Cooper #endif 203f44eb013SEnji Cooper result = aio_return(kq_iocb); 204f44eb013SEnji Cooper #ifdef DEBUG 205f44eb013SEnji Cooper printf("Return Result for %d is %d\n\n", j, result); 206f44eb013SEnji Cooper #endif 207f44eb013SEnji Cooper if (result != sizeof(buffer)) { 208f44eb013SEnji Cooper printf("FAIL: run %d, operation %d, result %d " 209f44eb013SEnji Cooper " (errno=%d) should be %zu\n", run, pending, 210f44eb013SEnji Cooper result, errno, sizeof(buffer)); 211f44eb013SEnji Cooper failed++; 212f44eb013SEnji Cooper } else 213f44eb013SEnji Cooper printf("PASS: run %d, left %d\n", run, 214f44eb013SEnji Cooper pending - 1); 215f44eb013SEnji Cooper 216f44eb013SEnji Cooper free(kq_iocb); 217f44eb013SEnji Cooper iocb[j] = NULL; 218f44eb013SEnji Cooper pending--; 219f44eb013SEnji Cooper i++; 220f44eb013SEnji Cooper } 221f44eb013SEnji Cooper 222c52ef9bbSAlan Somers for (i = 0; i < max_queue_per_proc; i++) 223f44eb013SEnji Cooper free(iocb[i]); 224f44eb013SEnji Cooper 225f44eb013SEnji Cooper } 226f44eb013SEnji Cooper 227f44eb013SEnji Cooper if (tmp_file) 228f44eb013SEnji Cooper unlink(pathname); 229f44eb013SEnji Cooper 230f44eb013SEnji Cooper if (failed != 0) 231f44eb013SEnji Cooper printf("FAIL: %d tests failed\n", failed); 232f44eb013SEnji Cooper else 233f44eb013SEnji Cooper printf("PASS: All tests passed\n"); 234f44eb013SEnji Cooper 235f44eb013SEnji Cooper exit (failed == 0 ? 0 : 1); 236f44eb013SEnji Cooper } 237