1142976Sambrisko/*- 2142976Sambrisko * Copyright (C) 2005 IronPort Systems, Inc. All rights reserved. 3142976Sambrisko * 4142976Sambrisko * Redistribution and use in source and binary forms, with or without 5142976Sambrisko * modification, are permitted provided that the following conditions 6142976Sambrisko * are met: 7142976Sambrisko * 1. Redistributions of source code must retain the above copyright 8142976Sambrisko * notice, this list of conditions and the following disclaimer. 9142976Sambrisko * 2. Redistributions in binary form must reproduce the above copyright 10142976Sambrisko * notice, this list of conditions and the following disclaimer in the 11142976Sambrisko * documentation and/or other materials provided with the distribution. 12142976Sambrisko * 13142976Sambrisko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14142976Sambrisko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15142976Sambrisko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16142976Sambrisko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17142976Sambrisko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18142976Sambrisko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19142976Sambrisko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20142976Sambrisko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21142976Sambrisko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22142976Sambrisko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23142976Sambrisko * SUCH DAMAGE. 24142976Sambrisko * 25142976Sambrisko * $FreeBSD$ 26142976Sambrisko */ 27142976Sambrisko 28142976Sambrisko/* 29142976Sambrisko * Note: it is a good idea to run this against a physical drive to 30142976Sambrisko * exercise the physio fast path (ie. lio_kqueue /dev/<something safe>) 31142976Sambrisko * This will ensure op's counting is correct. It is currently broken. 32142976Sambrisko * 33142976Sambrisko * Also note that LIO & kqueue is not implemented in FreeBSD yet, LIO 34142976Sambrisko * is also broken with respect to op's and some paths. 35142976Sambrisko * 36142976Sambrisko * A patch to make this work is at: 37142976Sambrisko * http://www.ambrisko.com/doug/listio_kqueue/listio_kqueue.patch 38142976Sambrisko */ 39142976Sambrisko 40142976Sambrisko#include <aio.h> 41142976Sambrisko#include <fcntl.h> 42142976Sambrisko#include <stdio.h> 43142976Sambrisko#include <errno.h> 44142976Sambrisko#include <sys/types.h> 45142976Sambrisko#include <sys/event.h> 46142976Sambrisko#include <sys/time.h> 47142976Sambrisko#include <unistd.h> 48142976Sambrisko 49142976Sambrisko#define PATH_TEMPLATE "/tmp/aio.XXXXXXXXXX" 50142976Sambrisko 51142976Sambrisko#define LIO_MAX 5 52142976Sambrisko#define MAX LIO_MAX * 16 53142976Sambrisko#define MAX_RUNS 300 54142976Sambrisko 55142976Sambriskomain(int argc, char *argv[]){ 56142976Sambrisko int fd; 57142976Sambrisko struct aiocb *iocb[MAX], *kq_iocb; 58142976Sambrisko struct aiocb **lio[LIO_MAX], **lio_element, **kq_lio; 59142976Sambrisko int i, result, run, error, j, k; 60142976Sambrisko char buffer[32768]; 61142976Sambrisko int kq = kqueue(); 62142976Sambrisko struct kevent ke, kq_returned; 63142976Sambrisko struct timespec ts; 64142976Sambrisko struct sigevent sig; 65142976Sambrisko time_t time1, time2; 66142976Sambrisko char *file, pathname[sizeof(PATH_TEMPLATE)-1]; 67142976Sambrisko int tmp_file = 0, failed = 0; 68142976Sambrisko 69142976Sambrisko if (kq < 0) { 70142976Sambrisko perror("No kqeueue\n"); 71142976Sambrisko exit(1); 72142976Sambrisko } 73142976Sambrisko 74142976Sambrisko if (argc == 1) { 75142976Sambrisko strcpy(pathname, PATH_TEMPLATE); 76142976Sambrisko fd = mkstemp(pathname); 77142976Sambrisko file = pathname; 78142976Sambrisko tmp_file = 1; 79142976Sambrisko } else { 80142976Sambrisko file = argv[1]; 81142976Sambrisko fd = open(file, O_RDWR|O_CREAT, 0666); 82142976Sambrisko } 83142976Sambrisko if (fd < 0){ 84142976Sambrisko fprintf(stderr, "Can't open %s\n", argv[1]); 85142976Sambrisko perror(""); 86142976Sambrisko exit(1); 87142976Sambrisko } 88142976Sambrisko 89142976Sambrisko#ifdef DEBUG 90142976Sambrisko printf("Hello kq %d fd %d\n", kq, fd); 91142976Sambrisko#endif 92142976Sambrisko 93142976Sambrisko for (run = 0; run < MAX_RUNS; run++){ 94142976Sambrisko#ifdef DEBUG 95142976Sambrisko printf("Run %d\n", run); 96142976Sambrisko#endif 97142976Sambrisko for (j = 0; j < LIO_MAX; j++) { 98142976Sambrisko lio[j] = (struct aiocb **) 99142976Sambrisko malloc(sizeof(struct aiocb *) * MAX/LIO_MAX); 100142976Sambrisko for(i = 0; i < MAX / LIO_MAX; i++) { 101142976Sambrisko k = (MAX / LIO_MAX * j) + i; 102142976Sambrisko lio_element = lio[j]; 103142976Sambrisko lio[j][i] = iocb[k] = (struct aiocb *) 104142976Sambrisko malloc(sizeof(struct aiocb)); 105142976Sambrisko bzero(iocb[k], sizeof(struct aiocb)); 106142976Sambrisko iocb[k]->aio_nbytes = sizeof(buffer); 107142976Sambrisko iocb[k]->aio_buf = buffer; 108142976Sambrisko iocb[k]->aio_fildes = fd; 109142976Sambrisko iocb[k]->aio_offset 110142976Sambrisko = iocb[k]->aio_nbytes * k * (run + 1); 111142976Sambrisko 112142976Sambrisko#ifdef DEBUG 113142976Sambrisko printf("hello iocb[k] %d\n", 114142976Sambrisko iocb[k]->aio_offset); 115142976Sambrisko#endif 116142976Sambrisko iocb[k]->aio_lio_opcode = LIO_WRITE; 117142976Sambrisko } 118142976Sambrisko sig.sigev_notify_kqueue = kq; 119154668Sdavidxu sig.sigev_value.sival_ptr = lio[j]; 120142976Sambrisko sig.sigev_notify = SIGEV_KEVENT; 121142976Sambrisko time(&time1); 122142976Sambrisko result = lio_listio(LIO_NOWAIT, lio[j], 123142976Sambrisko MAX / LIO_MAX, &sig); 124142976Sambrisko error = errno; 125142976Sambrisko time(&time2); 126142976Sambrisko#ifdef DEBUG 127142976Sambrisko printf("Time %d %d %d result -> %d\n", 128142976Sambrisko time1, time2, time2-time1, result); 129142976Sambrisko#endif 130142976Sambrisko if (result != 0) { 131142976Sambrisko errno = error; 132142976Sambrisko perror("list_listio"); 133142976Sambrisko printf("FAIL: Result %d iteration %d\n",result, j); 134142976Sambrisko exit(1); 135142976Sambrisko } 136142976Sambrisko#ifdef DEBUG 137142976Sambrisko printf("write %d is at %p\n", j, lio[j]); 138142976Sambrisko#endif 139142976Sambrisko } 140142976Sambrisko 141142976Sambrisko for(i = 0; i < LIO_MAX; i++) { 142142976Sambrisko for(j = LIO_MAX - 1; j >=0; j--) { 143142976Sambrisko if (lio[j]) 144142976Sambrisko break; 145142976Sambrisko } 146142976Sambrisko 147142976Sambrisko for(;;) { 148142976Sambrisko bzero(&ke, sizeof(ke)); 149142976Sambrisko bzero(&kq_returned, sizeof(ke)); 150142976Sambrisko ts.tv_sec = 0; 151142976Sambrisko ts.tv_nsec = 1; 152142976Sambrisko#ifdef DEBUG 153142976Sambrisko printf("FOO lio %d -> %p\n", j, lio[j]); 154142976Sambrisko#endif 155142976Sambrisko EV_SET(&ke, (uintptr_t)lio[j], 156142976Sambrisko EVFILT_LIO, EV_ONESHOT, 0, 0, iocb[j]); 157142976Sambrisko result = kevent(kq, NULL, 0, 158142976Sambrisko &kq_returned, 1, &ts); 159142976Sambrisko error = errno; 160142976Sambrisko if (result < 0) { 161142976Sambrisko perror("kevent error: "); 162142976Sambrisko } 163142976Sambrisko kq_lio = kq_returned.udata; 164142976Sambrisko#ifdef DEBUG 165142976Sambrisko printf("kevent %d %d errno %d return.ident %p " 166142976Sambrisko "return.data %p return.udata %p %p\n", 167142976Sambrisko i, result, error, 168142976Sambrisko kq_returned.ident, kq_returned.data, 169142976Sambrisko kq_returned.udata, 170142976Sambrisko lio[j]); 171142976Sambrisko#endif 172142976Sambrisko 173142976Sambrisko if(kq_lio) 174142976Sambrisko break; 175142976Sambrisko#ifdef DEBUG 176142976Sambrisko printf("Try again\n"); 177142976Sambrisko#endif 178142976Sambrisko } 179142976Sambrisko 180142976Sambrisko#ifdef DEBUG 181142976Sambrisko printf("lio %p\n", lio); 182142976Sambrisko#endif 183142976Sambrisko 184142976Sambrisko for (j = 0; j < LIO_MAX; j++) { 185142976Sambrisko if (lio[j] == kq_lio) { 186142976Sambrisko break; 187142976Sambrisko } 188142976Sambrisko } 189142976Sambrisko if (j == LIO_MAX) { 190142976Sambrisko printf("FAIL:\n"); 191142976Sambrisko exit(1); 192142976Sambrisko } 193142976Sambrisko 194142976Sambrisko#ifdef DEBUG 195142976Sambrisko printf("Error Result for %d is %d\n", j, result); 196142976Sambrisko#endif 197142976Sambrisko if (result < 0) { 198142976Sambrisko printf("FAIL: run %d, operation %d result %d \n", run, LIO_MAX - i -1, result); 199142976Sambrisko failed = 1; 200142976Sambrisko } else { 201142976Sambrisko printf("PASS: run %d, operation %d result %d \n", run, LIO_MAX - i -1, result); 202142976Sambrisko } 203142976Sambrisko for(k = 0; k < MAX / LIO_MAX; k++){ 204142976Sambrisko result = aio_return(kq_lio[k]); 205142976Sambrisko#ifdef DEBUG 206142976Sambrisko printf("Return Resulto for %d %d is %d\n", j, k, result); 207142976Sambrisko#endif 208142976Sambrisko if (result != sizeof(buffer)) { 209142976Sambrisko printf("FAIL: run %d, operation %d sub-opt %d result %d (errno=%d) should be %d\n", 210142976Sambrisko run, LIO_MAX - i -1, k, result, errno, sizeof(buffer)); 211142976Sambrisko } else { 212142976Sambrisko printf("PASS: run %d, operation %d sub-opt %d result %d\n", 213142976Sambrisko run, LIO_MAX - i -1, k, result); 214142976Sambrisko } 215142976Sambrisko } 216142976Sambrisko#ifdef DEBUG 217142976Sambrisko printf("\n"); 218142976Sambrisko#endif 219142976Sambrisko 220142976Sambrisko for(k = 0; k < MAX / LIO_MAX; k++) { 221142976Sambrisko free(lio[j][k]); 222142976Sambrisko } 223142976Sambrisko free(lio[j]); 224142976Sambrisko lio[j] = NULL; 225142976Sambrisko } 226142976Sambrisko } 227142976Sambrisko#ifdef DEBUG 228142976Sambrisko printf("Done\n"); 229142976Sambrisko#endif 230142976Sambrisko 231142976Sambrisko if (tmp_file) { 232142976Sambrisko unlink(pathname); 233142976Sambrisko } 234142976Sambrisko 235142976Sambrisko if (failed) { 236142976Sambrisko printf("FAIL: Atleast one\n"); 237142976Sambrisko exit(1); 238142976Sambrisko } else { 239142976Sambrisko printf("PASS: All\n"); 240142976Sambrisko exit(0); 241142976Sambrisko } 242142976Sambrisko} 243