JNIEXPORT void JNICALL Java_org_apache_activemq_artemis_jlibaio_LibaioContext_submitWrite (JNIEnv * env, jclass clazz, jint fileHandle, jobject contextPointer, jlong position, jint size, jobject bufferWrite, jobject callback) { struct io_control * theControl = getIOControl(env, contextPointer); if (theControl == NULL) { return; } #ifdef DEBUG fprintf (stdout, "submitWrite position %ld, size %d\n", position, size); #endif struct iocb * iocb = getIOCB(theControl); if (iocb == NULL) { throwIOException(env, "Not enough space in libaio queue"); return; } io_prep_pwrite(iocb, fileHandle, getBuffer(env, bufferWrite), (size_t)size, position); // The GlobalRef will be deleted when poll is called. this is done so // the vm wouldn't crash if the Callback passed by the user is GCed between submission // and callback. // also as the real intention is to hold the reference until the life cycle is complete iocb->data = (void *) (*env)->NewGlobalRef(env, callback); submit(env, theControl, iocb); }
int o2test_aio_pwrite(struct o2test_aio *o2a, int fd, void *buf, size_t count, off_t offset) { int ret = 0; struct iocb *iocbs[] = { o2a->o2a_iocbs[o2a->o2a_cr_event] }; if (o2a->o2a_cr_event >= o2a->o2a_nr_events) { fprintf(stderr, "current aio context didn't support %d " "requests\n", o2a->o2a_cr_event); return -1; } io_prep_pwrite(o2a->o2a_iocbs[o2a->o2a_cr_event], fd, buf, count, offset); ret = io_submit(o2a->o2a_ctx, 1, iocbs); if (ret != 1) { ret = errno; fprintf(stderr, "error %s during %s\n", strerror(errno), "io_submit"); ret = -1; } o2a->o2a_cr_event++; return ret; }
/* * Read complete callback. * Change read iocb into a write iocb and start it. */ static void rd_done(io_context_t ctx, struct iocb *iocb, long res, long res2) { /* library needs accessors to look at iocb? */ int iosize = iocb->u.c.nbytes; char *buf = iocb->u.c.buf; off_t offset = iocb->u.c.offset; if (res2 != 0) io_error("aio read", res2); if (res != iosize) { fprintf(stderr, "read missing bytes expect %lu got %ld\n", iocb->u.c.nbytes, res); exit(1); } /* turn read into write */ if (no_write) { --tocopy; --busy; free_iocb(iocb); } else { io_prep_pwrite(iocb, dstfd, buf, iosize, offset); io_set_callback(iocb, wr_done); if (1 != (res = io_submit(ctx, 1, &iocb))) io_error("io_submit write", res); } if (debug) write(2, "r", 1); if (debug > 1) printf("%d", iosize); }
ssize_t file_pwrite(unsigned int file_id, void *buf, ssize_t count, long long offset, int thread_id) { FILE_DESCRIPTOR fd = files[file_id]; #ifdef HAVE_MMAP void *start; size_t page_addr; size_t page_offset; #endif #ifdef HAVE_LIBAIO struct iocb iocb; #else (void)thread_id; /* unused */ #endif if (file_io_mode == FILE_IO_MODE_SYNC) return pwrite(fd, buf, count, offset); #ifdef HAVE_LIBAIO else if (file_io_mode == FILE_IO_MODE_ASYNC) { /* Use asynchronous write */ io_prep_pwrite(&iocb, fd, buf, count, offset); if (file_submit_or_wait(&iocb, FILE_OP_TYPE_WRITE, count, thread_id)) return 0; return count; } #endif #ifdef HAVE_MMAP else if (file_io_mode == FILE_IO_MODE_MMAP) { # if SIZEOF_SIZE_T == 4 /* Create file mapping for each I/O operation on 32-bit platforms */ page_addr = offset & file_page_mask; page_offset = offset - page_addr; start = mmap(NULL, count + page_offset, PROT_READ | PROT_WRITE, MAP_SHARED, fd, page_addr); if (start == MAP_FAILED) return 0; memcpy((char *)start + page_offset, buffer, count); munmap(start, count + page_offset); return count; # else (void)start; /* unused */ (void)page_addr; /* unused */ (void)page_offset; /* unused */ /* We already have all files mapped on 64-bit platforms */ memcpy((char *)mmaps[file_id] + offset, buffer, count); return count; # endif } #endif /* HAVE_MMAP */ return 0; /* Unknown I/O mode */ }
static int sector_io(struct sbd_context *st, int sector, void *data, int rw) { struct timespec timeout; struct io_event event; struct iocb *ios[1] = { &st->io }; long r; timeout.tv_sec = timeout_io; timeout.tv_nsec = 0; memset(&st->io, 0, sizeof(struct iocb)); if (rw) { io_prep_pwrite(&st->io, st->devfd, data, sector_size, sector_size * sector); } else { io_prep_pread(&st->io, st->devfd, data, sector_size, sector_size * sector); } if (io_submit(st->ioctx, 1, ios) != 1) { cl_log(LOG_ERR, "Failed to submit IO request! (rw=%d)", rw); return -1; } errno = 0; r = io_getevents(st->ioctx, 1L, 1L, &event, &timeout); if (r < 0 ) { cl_log(LOG_ERR, "Failed to retrieve IO events (rw=%d)", rw); return -1; } else if (r < 1L) { cl_log(LOG_INFO, "Cancelling IO request due to timeout (rw=%d)", rw); r = io_cancel(st->ioctx, ios[0], &event); if (r) { DBGLOG(LOG_INFO, "Could not cancel IO request (rw=%d)", rw); /* Doesn't really matter, debugging information. */ } return -1; } else if (r > 1L) { cl_log(LOG_ERR, "More than one IO was returned (r=%ld)", r); return -1; } /* IO is happy */ if (event.res == sector_size) { return 0; } else { cl_log(LOG_ERR, "Short IO (rw=%d, res=%lu, sector_size=%d)", rw, event.res, sector_size); return -1; } }
/* * build an aio iocb for an operation, based on oper->rw and the * last offset used. This finds the struct io_unit that will be attached * to the iocb, and things are ready for submission to aio after this * is called. * * returns null on error */ static struct io_unit *build_iocb(struct thread_info *t, struct io_oper *oper) { struct io_unit *io; off_t rand_byte; io = find_iou(t, oper); if (!io) { fprintf(stderr, "unable to find io unit\n"); return NULL; } switch(oper->rw) { case WRITE: io_prep_pwrite(&io->iocb,oper->fd, io->buf, oper->reclen, oper->last_offset); oper->last_offset += oper->reclen; break; case READ: io_prep_pread(&io->iocb,oper->fd, io->buf, oper->reclen, oper->last_offset); oper->last_offset += oper->reclen; break; case RREAD: rand_byte = random_byte_offset(oper); oper->last_offset = rand_byte; io_prep_pread(&io->iocb,oper->fd, io->buf, oper->reclen, rand_byte); break; case RWRITE: rand_byte = random_byte_offset(oper); oper->last_offset = rand_byte; io_prep_pwrite(&io->iocb,oper->fd, io->buf, oper->reclen, rand_byte); break; } return io; }
int aio_write(int fd, void *buffer, size_t length, off_t offset, aio_callback_t cb){ struct iocb iocb; struct iocb *piocb = &iocb; int resp; io_prep_pwrite(&iocb, fd, buffer, length, offset); iocb.data = cb; io_set_eventfd(&iocb, aio_fd); resp = io_submit(aio_ctx,1, &piocb); return resp; }
JNIEXPORT void JNICALL Java_org_apache_activemq_artemis_jlibaio_LibaioContext_deleteContext(JNIEnv* env, jclass clazz, jobject contextPointer) { int i; struct io_control * theControl = getIOControl(env, contextPointer); if (theControl == NULL) { return; } struct iocb * iocb = getIOCB(theControl); if (iocb == NULL) { throwIOException(env, "Not enough space in libaio queue"); return; } // Submitting a dumb write so the loop finishes io_prep_pwrite(iocb, dumbWriteHandler, 0, 0, 0); iocb->data = (void *) -1; if (!submit(env, theControl, iocb)) { return; } // to make sure the poll has finished pthread_mutex_lock(&(theControl->pollLock)); pthread_mutex_unlock(&(theControl->pollLock)); // To return any pending IOCBs int result = io_getevents(theControl->ioContext, 0, 1, theControl->events, 0); for (i = 0; i < result; i++) { struct io_event * event = &(theControl->events[i]); struct iocb * iocbp = event->obj; putIOCB(theControl, iocbp); } io_queue_release(theControl->ioContext); pthread_mutex_destroy(&(theControl->pollLock)); pthread_mutex_destroy(&(theControl->iocbLock)); // Releasing each individual iocb for (i = 0; i < theControl->queueSize; i++) { free(theControl->iocb[i]); } (*env)->DeleteGlobalRef(env, theControl->thisObject); free(theControl->iocb); free(theControl->events); free(theControl); }
static void aiobe_pwrite(struct device* dev, void* buf, size_t size, off64_t offset, dev_callback_t cb, void* cookie) { int ret; struct aiobe_request* req=(struct aiobe_request*)malloc(sizeof(struct aiobe_request)); struct iocb* iocb = &req->iocb; memset(req, 0, sizeof(*req)); io_prep_pwrite(iocb, D(dev)->fd, buf, size, offset); req->cb=cb; req->cookie=cookie; iocb->data = req; ret=io_submit(D(dev)->ctx, 1, &iocb); if (ret!=1) aiobe_complete(req, -1); }
aiom_cb_t * mb_aiom_prep_pwrite (mb_aiom_t *aiom, int fd, void *buf, size_t count, long long offset) { aiom_cb_t *aiom_cb; if (NULL == (aiom_cb = mb_res_pool_pop(aiom->cbpool))) { return NULL; } io_prep_pwrite(&aiom_cb->iocb, fd, buf, count, offset); GETTIMEOFDAY(&aiom_cb->submit_time); aiom->pending[aiom->nr_pending++] = aiom_cb; return aiom_cb; }
/* * Test whether counter overflow is detected and handled correctly. * * It is not possible to directly overflow the counter using the * write() syscall. Overflows occur when the counter is incremented * from kernel space, in an irq context, when it is not possible to * block the calling thread of execution. * * The AIO subsystem internally uses eventfd mechanism for * notification of completion of read or write requests. In this test * we trigger a counter overflow, by setting the counter value to the * max possible value initially. When the AIO subsystem notifies * through the eventfd counter, the counter overflows. * * NOTE: If the the counter starts from an initial value of 0, it will * take decades for an overflow to occur. But since we set the initial * value to the max possible counter value, we are able to cause it to * overflow with a single increment. * * When the counter overflows, the following are tested * 1. Check whether POLLERR event occurs in poll() for the eventfd. * 2. Check whether readfd_set/writefd_set is set in select() for the eventfd. * 3. The counter value is UINT64_MAX. */ static int trigger_eventfd_overflow(int evfd, int *fd, io_context_t * ctx) { int ret; struct iocb iocb; struct iocb *iocbap[1]; static char buf[4 * 1024]; *ctx = 0; ret = io_setup(16, ctx); if (ret < 0) { errno = -ret; tst_resm(TINFO | TERRNO, "io_setup error"); return -1; } *fd = open("testfile", O_RDWR | O_CREAT, 0644); if (*fd == -1) { tst_resm(TINFO | TERRNO, "open(testfile) failed"); goto err_io_destroy; } ret = set_counter(evfd, UINT64_MAX - 1); if (ret == -1) { tst_resm(TINFO, "error setting counter to UINT64_MAX-1"); goto err_close_file; } io_prep_pwrite(&iocb, *fd, buf, sizeof(buf), 0); io_set_eventfd(&iocb, evfd); iocbap[0] = &iocb; ret = io_submit(*ctx, 1, iocbap); if (ret < 0) { errno = -ret; tst_resm(TINFO | TERRNO, "error submitting iocb"); goto err_close_file; } return 0; err_close_file: close(*fd); err_io_destroy: io_destroy(*ctx); return -1; }
void RandomAccessFileDevice::prepareTransfer(RandomAccessRequest &request) { assert(request.pDevice == this); #ifdef USE_AIO_H int aio_lio_opcode = (request.type == RandomAccessRequest::READ) ? LIO_READ : LIO_WRITE; FileSize cbOffset = request.cbOffset; for (RandomAccessRequest::BindingListIter bindingIter(request.bindingList); bindingIter; ++bindingIter) { RandomAccessRequestBinding *pBinding = bindingIter; pBinding->aio_fildes = handle; pBinding->aio_lio_opcode = aio_lio_opcode; // TODO: initialize constant fields below only once pBinding->aio_buf = pBinding->getBuffer(); pBinding->aio_nbytes = pBinding->getBufferSize(); pBinding->aio_reqprio = 0; pBinding->aio_offset = cbOffset; cbOffset += pBinding->aio_nbytes; } assert(cbOffset == request.cbOffset + request.cbTransfer); #endif #ifdef USE_LIBAIO_H FileSize cbOffset = request.cbOffset; for (RandomAccessRequest::BindingListIter bindingIter(request.bindingList); bindingIter; ++bindingIter) { RandomAccessRequestBinding *pBinding = bindingIter; if (request.type == RandomAccessRequest::READ) { io_prep_pread( pBinding, handle, pBinding->getBuffer(), pBinding->getBufferSize(), cbOffset); } else { io_prep_pwrite( pBinding, handle, pBinding->getBuffer(), pBinding->getBufferSize(), cbOffset); } cbOffset += pBinding->getBufferSize(); } assert(cbOffset == request.cbOffset + request.cbTransfer); #endif }
int aio_enqueue( int fd, char *buf, unsigned long size, unsigned long start_addr, OPERATION_TYPE op ) { int rtn; int queue_id; struct iocb *cb; int i; retry: queue_id = find_and_set_id(); if(queue_id == -1){ PRINT("Qbusy "); usleep(10); goto retry; } my_iocbp[queue_id].qid = queue_id; cb = &my_iocbp[queue_id].iocbp; switch (op){ case WG_READ: io_prep_pread(cb, fd, buf, size, start_addr); break; case WG_WRITE: io_prep_pwrite(cb, fd, buf, size, start_addr); break; default: PRINT("Error not supported I/O operation file:%s, line:%d\n", __func__, __LINE__); exit(1); } rtn = io_submit(context, 1, &cb); if(rtn<0){ PRINT("Error on I/O submission, line:%d, errno:%d\n", __LINE__, rtn); exit(1); } pthread_mutex_lock(&aio_req_num_mutex); req_num++; pthread_mutex_unlock(&aio_req_num_mutex); return rtn; }
int aioperf_libaio_write(aioperf_io_task_t *io_task) { struct iocb *libaio_req = NULL; aioperf_repository_t *repository = NULL; aioperf_conf_info_t *conf_info = NULL; unsigned long left_size = 0; unsigned int count = 0; repository = io_task->repository; conf_info = repository->conf_info; left_size = io_task->file_size - io_task->offset; if (!(libaio_req = (struct iocb *)aioperf_memory_pool_alloc(repository->pool, sizeof(struct iocb)))) { printf("alloc error\n"); return AIOPERF_ERROR; } aioperf_memory_set(libaio_req, 0, sizeof(struct iocb)); io_task->data = libaio_req; if (left_size > conf_info->buf_size) { count = conf_info->buf_size; } else { count = left_size; } io_prep_pwrite(libaio_req, io_task->fd, repository->buf, count, io_task->offset); libaio_req->data = io_task; io_set_eventfd(libaio_req, io_task->repository->signal_fd); if (io_submit(*(io_context_t *)repository->mgr->data, 1, &libaio_req) < 0) { printf("io_submit error\n"); } return AIOPERF_OK; }
static int do_aio_loop(int fd, void *buf) { int err, ret; struct io_context *ctx = NULL; struct io_event ev; struct iocb iocb, *iocbs[] = { &iocb }; struct timeval start, now, delta = { 0, 0 }; ret = 0; err = io_setup(1, &ctx); if (err) { fprintf(stderr, "error %s during %s\n", strerror(-err), "io_setup" ); return 1; } gettimeofday(&start, NULL); while (1) { io_prep_pwrite(&iocb, fd, buf, BUF_SIZE, BUF_SIZE); err = io_submit(ctx, 1, iocbs); if (err != 1) { fprintf(stderr, "error %s during %s\n", strerror(-err), "io_submit"); ret = 1; break; } err = io_getevents(ctx, 1, 1, &ev, NULL); if (err != 1) { fprintf(stderr, "error %s during %s\n", strerror(-err), "io_getevents"); ret = 1; break; } gettimeofday(&now, NULL); timersub(&now, &start, &delta); if (delta.tv_sec >= LOOP_SECONDS) break; } io_destroy(ctx); return ret; }
static void rd_done(io_context_t ctx, struct iocb *iocb, long res, long res2) { /*library needs accessors to look at iocb*/ int iosize = iocb->u.c.nbytes; char *buf = (char *)iocb->u.c.buf; off_t offset = iocb->u.c.offset; int tmp; char *wrbuff = NULL; if(res2 != 0) { printf("aio read\n"); } if(res != iosize) { printf("read missing bytes expect %lu got %ld", iocb->u.c.nbytes, res); //exit(1); } /*turn read into write*/ tmp = posix_memalign((void **)&wrbuff, getpagesize(), AIO_BLKSIZE); if(tmp < 0) { printf("posix_memalign222\n"); exit(1); } snprintf(wrbuff, iosize + 1, "%s", buf); printf("wrbuff-len = %lu:%s\n", strlen(wrbuff), wrbuff); printf("wrbuff_len = %lu\n", strlen(wrbuff)); free(buf); io_prep_pwrite(iocb, odsfd, wrbuff, iosize, offset); io_set_callback(iocb, wr_done); if(1!= (res=io_submit(ctx, 1, &iocb))) printf("io_submit write error\n"); printf("\nsubmit %ld write request\n", res); }
static void do_io_async(void) { size_t n_files = sizeof(files) / sizeof(files[0]); size_t i; io_context_t ctx = 0; struct iocb *iocb; struct iocb **piocb; int n_aio_ops, rc; /* TODO 1 - allocate iocb and piocb */ iocb = (struct iocb *) malloc(n_files * sizeof(*iocb)); DIE(iocb == NULL, "malloc"); piocb = (struct iocb **) malloc(n_files * sizeof(*piocb)); DIE(piocb == NULL, "malloc"); /* TODO 1 - initialiaze iocb and piocb */ for (i = 0; i < n_files; i++) { io_prep_pwrite(&iocb[i], fds[i], g_buffer, BUFSIZ, 0); piocb[i] = &iocb[i]; #ifdef USE_EVENTFD /* TODO 2 - set up eventfd notification */ io_set_eventfd(&iocb[i], efd); #endif } /* TODO 1 - setup aio context */ rc = io_setup(n_files, &ctx); DIE(rc < 0, "io_setup"); /* TODO 1 - submit aio */ n_aio_ops = io_submit(ctx, n_files, piocb); DIE(n_aio_ops < 0, "io_submit"); /* wait for completion*/ wait_aio(ctx, n_files); /* TODO 1 - destroy aio context */ io_destroy(ctx); }
inline void prep_aio (struct iocb *this_iocb, const struct trace_entry *request) { struct object *obj = getobj (request->item->obj); char *ptr; if (request->rwType == 'R') io_prep_pread (this_iocb, lfs_n.fd, obj->obj_data->data, request->bytecount, request->startbyte); else if (request->rwType == 'W') { ptr = request->item->_ptr = getshmptr (request->item->shmid); if (ptr == NULL) { lfs_printf ("pre_aio failed"); assert (0); return; } lfs_printf ("prep_aio write\n"); io_prep_pwrite (this_iocb, lfs_n.fd, ptr, request->bytecount, request->startbyte); } }
int main(int argc, char *argv[]) { io_context_t ctx; struct io_event event; int io_event_cnt = 10; int fd; char *file = "hello.txt"; char *content = "1234567890"; char *content2 = "abcdefg"; struct timespec timeout; struct iocb io; struct iocb io2; struct iocb *p[2]; int ret; int total_write, finished; printf("hello aio.\n"); memset(&ctx, 0x0, sizeof(ctx)); if (0 != (ret = io_setup(io_event_cnt, &ctx))) { io_setup_error(ret); return -1; } if ((fd = open(file, O_CREAT|O_WRONLY, 0644)) < 0) { printf("open 1 error"); io_destroy(ctx); return -1; } io_prep_pwrite(&io, fd, content, strlen(content), 0); io_prep_pwrite(&io2, fd, content2, strlen(content2), 20); p[0] = &io; p[1] = &io2; total_write = 2; //进行两个文件的写入 finished = 0; if (2 != io_submit(ctx, 2, p)) { io_destroy(ctx); printf("io_submit error\n"); return -1; } printf("submitted\n"); timeout.tv_sec = 0; timeout.tv_nsec = 500000000; while(1) { if (1 == io_getevents(ctx, 0, 1, &event, &timeout)) { if (event.obj == &io) { printf("io 1 finished\n"); } if (event.obj == &io2) { printf("io 2 finished\n"); } finished++; if (finished == total_write) { break; } } } printf("finish write.\n"); close(fd); io_destroy(ctx); return 0; }
/* 一次提交多个io请求的操作 */ int io_tio(char *pathname, int flag, int n, int operation) { int res, fd = 0, i = 0; void *bufptr = NULL; off_t offset = 0; struct timespec timeout; io_context_t myctx; struct iocb iocb_array[AIO_MAXIO]; struct iocb *iocbps[AIO_MAXIO]; fd = open(pathname, flag, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (fd <= 0) { printf("open for %s failed: %s\n", pathname, strerror(errno)); return -1; } res = io_queue_init(n, &myctx); //printf (" res = %d \n", res); for (i = 0; i < AIO_MAXIO; i++) { switch (operation) { case IO_CMD_PWRITE: if (posix_memalign(&bufptr, alignment, AIO_BLKSIZE)) { perror(" posix_memalign failed "); return -1; } memset(bufptr, 0, AIO_BLKSIZE); io_prep_pwrite(&iocb_array[i], fd, bufptr, AIO_BLKSIZE, offset); io_set_callback(&iocb_array[i], work_done); iocbps[i] = &iocb_array[i]; offset += AIO_BLKSIZE; break; case IO_CMD_PREAD: if (posix_memalign(&bufptr, alignment, AIO_BLKSIZE)) { perror(" posix_memalign failed "); return -1; } memset(bufptr, 0, AIO_BLKSIZE); io_prep_pread(&iocb_array[i], fd, bufptr, AIO_BLKSIZE, offset); io_set_callback(&iocb_array[i], work_done); iocbps[i] = &iocb_array[i]; offset += AIO_BLKSIZE; break; case IO_CMD_POLL: case IO_CMD_NOOP: break; default: tst_resm(TFAIL, "Command failed; opcode returned: %d\n", operation); return -1; break; } } do { res = io_submit(myctx, AIO_MAXIO, iocbps); } while (res == -EAGAIN); if (res < 0) { io_error("io_submit tio", res); } /* * We have submitted all the i/o requests. Wait for at least one to complete * and call the callbacks. */ wait_count = AIO_MAXIO; timeout.tv_sec = 30; timeout.tv_nsec = 0; switch (operation) { case IO_CMD_PREAD: case IO_CMD_PWRITE: { while (wait_count) { res = io_wait_run(myctx, &timeout); if (res < 0) io_error("io_wait_run", res); } } break; } close(fd); for (i = 0; i < AIO_MAXIO; i++) { if (iocb_array[i].u.c.buf != NULL) { free(iocb_array[i].u.c.buf); } } io_queue_release(myctx); return 0; }
int main(int argc, char **argv) { int i, j, sec, usec; int failflag=0; int bflag=0, nflag=0, Fflag=0; char *optb, *optn, *optF; char *msg; /* for parse_opts */ struct io_event event; static struct timespec ts; struct timeval stv, etv; option_t options[] = { { "b:", &bflag, &optb }, { "n:", &nflag, &optn }, { "F:", &Fflag, &optF }, { NULL, NULL, NULL} }; msg = parse_opts(argc, argv, options, &help); if (msg != (char *) NULL) { tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); tst_exit(); } bufsize = (bflag ? atoi(optb):8192); nr = (nflag ? atoi(optn):10); if (Fflag) { sprintf(fname, optF); } else { sprintf(fname, "aiofile"); } setup(); /* TEST 1 */ pos = 0; gettimeofday(&stv, NULL); io_prep_pwrite(iocbs[0], fd, srcbuf, bufsize, pos); for (i = 0; i< nr; i++) { ts.tv_sec = 30; ts.tv_nsec = 0; do { TEST(io_submit(io_ctx, 1, iocbs)); } while (TEST_RETURN == -EAGAIN); if (TEST_RETURN < 0) { TEST_ERROR_LOG(TEST_ERRNO); tst_resm(TFAIL, "Test 1: io_submit failed - retval=%d, " "errno=%d", TEST_RETURN, TEST_ERRNO); failflag=1; continue; } while (io_getevents(io_ctx, 1, 1, &event, &ts) != 1); gettimeofday(&etv, NULL); } if (!failflag) { sec = etv.tv_sec - stv.tv_sec; usec = etv.tv_usec - stv.tv_usec; if (usec < 0) { usec += 1000000; sec--; } tst_resm(TPASS, "Test 1: %d writes in %3d.%06d sec", nr, sec, usec); } /* TEST 2 */ pos = 0; failflag=0; gettimeofday(&stv, NULL); io_prep_pread(iocbs[0], fd, dstbuf, bufsize, pos); for (i = 0; i< nr; i++) { ts.tv_sec = 30; ts.tv_nsec = 0; do { TEST(io_submit(io_ctx, 1, iocbs)); } while (TEST_RETURN == -EAGAIN); if (TEST_RETURN < 0) { TEST_ERROR_LOG(TEST_ERRNO); tst_resm(TFAIL, "Test 2: io_submit failed - retval=%d, " "errno=%d", TEST_RETURN, TEST_ERRNO); failflag=1; continue; } while (io_getevents(io_ctx, 1, 1, &event, &ts) != 1); gettimeofday(&etv, NULL); } if (!failflag) { sec = etv.tv_sec - stv.tv_sec; usec = etv.tv_usec - stv.tv_usec; if (usec < 0) { usec += 1000000; sec--; } tst_resm(TPASS, "Test 2: %d reads in %3d.%06d sec", nr, sec, usec); } /* TEST 3 */ pos = 0; failflag=0; gettimeofday(&stv, NULL); for (i = 0; i< nr; i++) { io_prep_pwrite(iocbs[0], fd, srcbuf, bufsize, pos); ts.tv_sec = 30; ts.tv_nsec = 0; do { TEST(io_submit(io_ctx, 1, iocbs)); } while (TEST_RETURN == -EAGAIN); if (TEST_RETURN < 0) { TEST_ERROR_LOG(TEST_ERRNO); tst_resm(TFAIL, "Test 3: io_submit failed - retval=%d, " "errno=%d", TEST_RETURN, TEST_ERRNO); failflag=1; continue; } while (io_getevents(io_ctx, 1, 1, &event, &ts) != 1); gettimeofday(&etv, NULL); } if (!failflag) { sec = etv.tv_sec - stv.tv_sec; usec = etv.tv_usec - stv.tv_usec; if (usec < 0) { usec += 1000000; sec--; } tst_resm(TPASS, "Test 3: %d prep,writes in %3d.%06d sec", nr, sec, usec); } /* TEST 4 */ pos = 0; failflag=0; gettimeofday(&stv, NULL); for (i = 0; i< nr; i++) { io_prep_pread(iocbs[0], fd, dstbuf, bufsize, pos); ts.tv_sec = 30; ts.tv_nsec = 0; do { TEST(io_submit(io_ctx, 1, iocbs)); } while (TEST_RETURN == -EAGAIN); if (TEST_RETURN < 0) { TEST_ERROR_LOG(TEST_ERRNO); tst_resm(TFAIL, "Test 4: io_submit failed - retval=%d, " "errno=%d", TEST_RETURN, TEST_ERRNO); failflag=1; continue; } while (io_getevents(io_ctx, 1, 1, &event, &ts) != 1); gettimeofday(&etv, NULL); } if (!failflag) { sec = etv.tv_sec - stv.tv_sec; usec = etv.tv_usec - stv.tv_usec; if (usec < 0) { usec += 1000000; sec--; } tst_resm(TPASS, "Test 4: %d prep,reads in %3d.%06d sec", nr, sec, usec); } /* TEST 5 */ pos = 0; failflag=0; gettimeofday(&stv, NULL); for (i = 0; i< nr; i++) { io_prep_pwrite(iocbs[0], fd, srcbuf, bufsize, pos); ts.tv_sec = 30; ts.tv_nsec = 0; do { TEST(io_submit(io_ctx, 1, iocbs)); } while (TEST_RETURN == -EAGAIN); if (TEST_RETURN < 0) { TEST_ERROR_LOG(TEST_ERRNO); tst_resm(TFAIL, "Test 5: write io_submit failed - " "retval=%d, errno=%d", TEST_RETURN, TEST_ERRNO); failflag=1; continue; } while (io_getevents(io_ctx, 1, 1, &event, &ts) != 1); io_prep_pread(iocbs[0], fd, dstbuf, bufsize, pos); ts.tv_sec = 30; ts.tv_nsec = 0; do { TEST(io_submit(io_ctx, 1, iocbs)); } while (TEST_RETURN == -EAGAIN); if (TEST_RETURN < 0) { TEST_ERROR_LOG(TEST_ERRNO); tst_resm(TFAIL, "Test 5: read io_submit failed - " "retval=%d, errno=%d", TEST_RETURN, TEST_ERRNO); failflag=1; continue; } while (io_getevents(io_ctx, 1, 1, &event, &ts) != 1); gettimeofday(&etv, NULL); } if (!failflag) { sec = etv.tv_sec - stv.tv_sec; usec = etv.tv_usec - stv.tv_usec; if (usec < 0) { usec += 1000000; sec--; } tst_resm(TPASS, "Test 5: %d reads and writes in %3d.%06d sec", nr, sec, usec); } /* TEST 6 */ pos = 0; failflag=0; gettimeofday(&stv, NULL); for (i = 0; i< nr; i++) { io_prep_pwrite(iocbs[0], fd, srcbuf, bufsize, pos); ts.tv_sec = 30; ts.tv_nsec = 0; do { TEST(io_submit(io_ctx, 1, iocbs)); } while (TEST_RETURN == -EAGAIN); if (TEST_RETURN < 0) { TEST_ERROR_LOG(TEST_ERRNO); tst_resm(TFAIL, "Test 6: write io_submit failed - " "retval=%d, errno=%d", TEST_RETURN, TEST_ERRNO); failflag=1; continue; } while (io_getevents(io_ctx, 1, 1, &event, &ts) != 1); io_prep_pread(iocbs[0], fd, dstbuf, bufsize, pos); ts.tv_sec = 30; ts.tv_nsec = 0; do { TEST(io_submit(io_ctx, 1, iocbs)); } while (TEST_RETURN == -EAGAIN); if (TEST_RETURN < 0) { TEST_ERROR_LOG(TEST_ERRNO); tst_resm(TFAIL, "Test 6: read io_submit failed - " "retval=%d, errno=%d", TEST_RETURN, TEST_ERRNO); failflag=1; continue; } while (io_getevents(io_ctx, 1, 1, &event, &ts) != 1); for (j = 0; j < bufsize; j++) { if (srcbuf[j] != dstbuf[j]) tst_resm(TFAIL, "Test 6: compare failed - " "read: %c, " "actual: %c", dstbuf[j], srcbuf[j]); break; } gettimeofday(&etv, NULL); } if (!failflag) { sec = etv.tv_sec - stv.tv_sec; usec = etv.tv_usec - stv.tv_usec; if (usec < 0) { usec += 1000000; sec--; } tst_resm(TPASS, "Test 6: %d read,write,verify in %d.%06d sec", i, sec, usec); } cleanup(); tst_exit(); }
void AsyncIOOp::pwrite(int fd, const void* buf, size_t size, off_t start) { init(); io_prep_pwrite(&iocb_, fd, const_cast<void*>(buf), size, start); }
int main(int argc, char *argv[]) { int fd, rc, j, k, nbytes = NBYTES, maxevents = NBUF; char *buf[NBUF], *filename = "/dev/mycdrv"; struct iocb *iocbray[NBUF], *iocb; off_t offset; io_context_t ctx = 0; struct io_event events[2 * NBUF]; struct timespec timeout = { 0, 0 }; /* open or create the file and fill it with a pattern */ if (argc > 1) filename = argv[1]; printf("opening %s\n", filename); /* notice opening with these flags won't hurt a device node! */ if ((fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) < 0) { printf("couldn't open %s, ABORTING\n", filename); exit(-1); } /* write initial data out, clear buffers, allocate iocb's */ for (j = 0; j < NBUF; j++) { /* no need to zero iocbs; will be done in io_prep_pread */ iocbray[j] = malloc(sizeof(struct iocb)); buf[j] = malloc(nbytes); sprintf(buf[j], "%4d%4d%4d%4d%4d%4d%4d%4d", j, j, j, j, j, j, j, j); write(fd, buf[j], nbytes); memset(buf[j], 0, nbytes); } printf("\n"); /* prepare the context */ rc = io_setup(maxevents, &ctx); printf(" rc from io_setup = %d\n", rc); /* (async) read the data from the file */ printf(" reading initial data from the file:\n"); for (j = 0; j < NBUF; j++) { iocb = iocbray[j]; offset = j * nbytes; io_prep_pread(iocb, fd, (void *)buf[j], nbytes, offset); rc = io_submit(ctx, 1, &iocb); } /* sync up and print out the readin data */ while ((rc = io_getevents(ctx, NBUF, NBUF, events, &timeout)) > 0) { printf(" rc from io_getevents on the read = %d\n\n", rc); } printbufs(buf, nbytes); /* filling in the buffers before the write */ for (j = 0; j < NBUF; j++) { char *tmp = buf[j]; for (k = 0; k < nbytes; k++) { sprintf((tmp + k), "%1d", j); } } /* write the changed buffers out */ printf(" writing new data to the file:\n"); for (j = 0; j < NBUF; j++) { iocb = iocbray[j]; offset = j * nbytes; io_prep_pwrite(iocb, fd, buf[j], nbytes, offset); rc = io_submit(ctx, 1, &iocb); } /* sync up again */ while ((rc = io_getevents(ctx, NBUF, NBUF, events, &timeout)) > 0) { printf(" rc from io_getevents on the write = %d\n\n", rc); } printbufs(buf, nbytes); /* clean up */ rc = io_destroy(ctx); close(fd); exit(0); }
int main() { size_t i; /* Attempt to read the MBR magic number from the device as a sanity check */ FILE *file = fopen("/dev/sdd", "r"); if (file == NULL) FATAL("Unable to open the device"); for (i = 0; i < SZ; i++) dest[0][i] = JUNK_VAL; size_t nr = fread(dest[0], SZ, 1, file); if (nr != 1) FATAL("Unable to read from the device"); fclose(file); if(dest[0][MAG_NUM_OFFSET1] != MAG_NUM_VAL1 || dest[0][MAG_NUM_OFFSET2] != MAG_NUM_VAL2) printf("Warning: Magic number not found during sanity check\n"); /* Open the device again, but get ready to use async IO this time */ int fd = open("/dev/sdd", O_NONBLOCK | O_DIRECT | O_RDWR, 0); if (fd < 0) FATAL("Error opening file"); /* Now use *real* asynchronous IO to read multiple chunks in parallel */ io_context_t ctx; memset(&ctx, 0, sizeof(ctx)); IO_RUN (__LINE__, io_queue_init, maxEvents, &ctx); /* This is the read job we asynchronously run */ struct iocb job_data[NUM_JOBS]; struct iocb *job = job_data; struct iocb *q[NUM_JOBS]; for (i = 0; i < SZ; i++) dest[0][i] = JUNK_VAL; for (i = 0; i < NUM_JOBS; i++,job++) { if (i & 1) io_prep_pread(job, fd, dest[i], SZ, i * SZ); else io_prep_pwrite(job, fd, dest[i], SZ, i * SZ); q[i] = job; } /* Issue it now */ job = job_data; IO_RUN (__LINE__, io_submit, ctx, NUM_JOBS, q); /* Wait for it */ struct timespec timeout; timeout.tv_sec = 5; timeout.tv_nsec = 0; struct io_event evts[NUM_JOBS]; IO_RUN (__LINE__, io_getevents, ctx, NUM_JOBS, NUM_JOBS, evts, &timeout); for (i = 0; i < NUM_JOBS; i++) { /* Confirm that the IOs completed successfully */ check(ctx, evts[i].obj, evts[i].res, evts[i].res2); } /* Only checking the first buffer, since the other ones were read from other locations */ if(dest[0][MAG_NUM_OFFSET1] != MAG_NUM_VAL1 || dest[0][MAG_NUM_OFFSET2] != MAG_NUM_VAL2) printf("Warning: Magic number not found during async read\n"); close(fd); io_destroy(ctx); return 0; }
int main(int argc, char **argv) { int run_time = 30; int op = O_RDONLY; int qd = 4; int end_of_device = 0; int opt, i, j, max_req, rc, ios_ready, in_flight, count; unsigned long arena_size; unsigned long seed = time(NULL); unsigned long mix_seed = time(NULL); unsigned long random_range = 0; unsigned char *arena; struct iocb *iocbs; struct iocb *ioptr; struct iocb **iolist; struct iocb **iolist_ptr; struct io_event *events; struct timespec start, end, now; unsigned long total_data, total_writes, total_count; int min_data, max_data; io_context_t ioctx; double mbs, actual_time; struct option options[] = { { "help", no_argument, NULL, 'h' }, { "write", optional_argument, NULL, 'w' }, { "loop", no_argument, NULL, 'l' }, { "mixseed", required_argument, NULL, 'm' }, { "qd", required_argument, NULL, 'q' }, { "random", optional_argument, NULL, 'r' }, { "range", required_argument, NULL, 'a' }, { "size", required_argument, NULL, 's' }, { "time", required_argument, NULL, 't' }, { NULL } }; req_size = 1024 * 1024; write_pct = 0.0; for (;;) { opt = getopt_long(argc, argv, "hwlq:s:t:", options, NULL); if (opt == -1) break; switch (opt) { case 'w': op = O_RDWR; write_pct = 1.0; if (optarg) write_pct = strtod(optarg, NULL) / 100.0; if (write_pct < 1.0) random_offsets = 1; break; case 'l': loop_at_end = 1; break; case 'm': mix_seed = strtoul(optarg, NULL, 0); break; case 'q': qd = atoi(optarg); break; case 't': run_time = atoi(optarg); break; case 's': req_size = strtoul(optarg, NULL, 0); break; case 'r': random_offsets = 1; if (optarg) seed = strtoul(optarg, NULL, 0); else seed = time(NULL); break; case 'a': random_range = strtoul(optarg, NULL, 0); break; case 'h': case '?': default: usage(argv[0]); break; } } if (run_time < 1) { fprintf(stderr, "%s: run time must be at least 1 second\n", argv[0]); exit(1); } if (qd < 0 || qd > 64) { fprintf(stderr, "%s: queue depth must be between 1 and 64\n", argv[0]); exit(1); } if (req_size < 4096 || req_size > (16 * 1024 * 1024)) { fprintf(stderr, "%s: request size must be between 4K and 16M\n", argv[0]); exit(1); } /* Always do a multiple of a page for direct IO. */ req_size &= ~4095; if (random_range) { random_range /= req_size; if (random_range < 2) { fprintf(stderr, "%s: random range gives no " "randomness\n", argv[0]); exit(1); } } if (optind == argc) { fprintf(stderr, "%s: need devices to benchmark\n", argv[0]); exit(1); } ndev = argc - optind; devs = malloc(ndev * sizeof(*devs)); if (!ndev) { fprintf(stderr, "%s: no memory for devices\n", argv[0]); exit(1); } for (i = 0; i < ndev; i++) { devs[i].replace = -1; devs[i].io_base = NULL; devs[i].offset = 0; devs[i].count = 0; devs[i].writes = 0; devs[i].status = ' '; devs[i].name = argv[optind++]; devs[i].fd = open(devs[i].name, op|O_DIRECT|O_SYNC); if (devs[i].fd < 0) { fprintf(stderr, "%s: opening ", argv[0]); perror(devs[i].name); exit(1); } devs[i].size = lseek(devs[i].fd, 0, SEEK_END); if (devs[i].size < 0) { fprintf(stderr, "%s: lseek ", argv[0]); perror(devs[i].name); exit(1); } if (random_offsets) { unsigned long t = seed + i; devs[i].random_range = devs[i].size / req_size; if (random_range && devs[i].random_range > random_range) devs[i].random_range = random_range; devs[i].off_rand_state[2] = t >> 16; devs[i].off_rand_state[1] = t & 0xffff; devs[i].off_rand_state[0] = 0x330e; t = mix_seed + i; devs[i].rw_rand_state[2] = t >> 16; devs[i].rw_rand_state[1] = t & 0xffff; devs[i].rw_rand_state[0] = 0x330e; } } /* The arena needs to be big enough to host the maximum number of * requests possible, plus an extra set of requests to pass around * the devices to fairly share any memory fragmentation seen. */ max_req = ndev * qd; arena_size = (max_req + qd) * req_size; arena = mmap(NULL, arena_size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_POPULATE|MAP_PRIVATE, -1, 0); if (arena == MAP_FAILED) { fprintf(stderr, "%s: unable to allocate arena\n", argv[0]); exit(1); } memset(arena, 0, arena_size); iocbs = malloc(max_req * sizeof(*iocbs)); if (!iocbs) { fprintf(stderr, "%s: no memory for IOCBs\n", argv[0]); exit(1); } iolist = malloc(max_req * sizeof(*iocbs)); if (!iolist) { fprintf(stderr, "%s: no memory for IOCB list\n", argv[0]); exit(1); } events = malloc(max_req * sizeof(*events)); if (!iolist) { fprintf(stderr, "%s: no memory for IOCB list\n", argv[0]); exit(1); } rc = io_queue_init(max_req, &ioctx); if (rc < 0) { fprintf(stderr, "%s: unable to initialize IO context: %s\n", argv[0], strerror(-rc)); exit(1); } /* Prepopulate our IO requests */ ios_ready = 0; ioptr = iocbs; iolist_ptr = iolist; for (i = 0; i < qd; i++) { for (j = 0; j < ndev; j++) { if (!devs[j].io_base) devs[j].io_base = ioptr; /* Initial iocb prep, will be overwritten in * prepare_request() with proper offset and operation. */ io_prep_pwrite(ioptr, devs[j].fd, arena, req_size, 0); ioptr->data = &devs[j]; arena += req_size; if (prepare_request(&devs[j], ioptr)) { fprintf(stderr, "Premature end of device for " "%s\n", devs[j].name); exit(1); } *iolist_ptr++ = ioptr++; ios_ready++; } } /* Populate the replacement list */ buf_dev = 0; buf_next = NULL; buf_ready = NULL; for (i = 0; i < qd; i++) { buf_p = (struct buf_list *) arena; buf_p->next = buf_ready; buf_ready = buf_p; arena += req_size; } clock_gettime(CLOCK_MONOTONIC_HR, &now); end.tv_sec = now.tv_sec + run_time; end.tv_nsec = now.tv_nsec; devs[0].replace = 0; in_flight = 0; clock_gettime(CLOCK_MONOTONIC_HR, &start); /* Prime the IO pump with our prepared requests */ rc = io_submit(ioctx, ios_ready, iolist); if (rc < 0) { fprintf(stderr, "%s: io_submit() failed: %s\n", argv[0], strerror(-rc)); exit(1); } in_flight += ios_ready; iolist_ptr = iolist; ios_ready = 0; /* Main IO loop */ while (time_before(&now, &end) && !end_of_device) { count = io_getevents(ioctx, 1, in_flight, events, NULL); if (count <= 0) { fprintf(stderr, "%s: io_getevents() failed: " "%s\n", argv[0], strerror(-rc)); exit(1); } for (i = 0; i < count && !end_of_device; i++) { struct iocb *iocb = events[i].obj; struct dev_info *dev = iocb->data; if (events[i].res2) { fprintf(stderr, "%s: got error for %s:" " %lu\n", argv[0], dev->name, events[i].res2); exit(1); } end_of_device = prepare_request(dev, iocb); if (!end_of_device) { *iolist_ptr++ = iocb; ios_ready++; } in_flight--; } /* If we're here, then odds are good we have IO to submit. * Check just in case something woke us up other than an * IO completion. */ if (ios_ready) { rc = io_submit(ioctx, ios_ready, iolist); if (rc < 0) { fprintf(stderr, "%s: io_submit() failed: %s\n", argv[0], strerror(-rc)); exit(1); } in_flight += ios_ready; iolist_ptr = iolist; ios_ready = 0; } clock_gettime(CLOCK_MONOTONIC_HR, &now); } if (end_of_device) { actual_time = now.tv_nsec - start.tv_nsec; actual_time /= 10e9; actual_time += now.tv_sec - start.tv_sec; } else actual_time = run_time; /* Ok, test time is finished, drain outstanding requests */ while (in_flight) { count = io_getevents(ioctx, 1, in_flight, events, NULL); if (count <= 0) { fprintf(stderr, "%s: draining io_getevents() failed: " "%s\n", argv[0], strerror(-rc)); exit(1); } for (i = 0; i < count; i++) { struct iocb *iocb = events[i].obj; struct dev_info *dev = iocb->data; if (events[i].res2) { fprintf(stderr, "%s: draining got error for %s:" " %lu\n", argv[0], dev->name, events[i].res2); exit(1); } in_flight--; } } /* Find the targets that wrote the min and max data so we can * calculate the skew. */ min_data = max_data = 0; total_data = total_writes = total_count= 0; for (i = 0; i < ndev; i++) { if (devs[i].count < devs[min_data].count) min_data = i; if (devs[i].count > devs[max_data].count) max_data = i; total_data += devs[i].count * req_size; total_writes += devs[i].writes; total_count += devs[i].count; } devs[min_data].status = 'm'; devs[max_data].status = 'M'; printf("run time: %.6f seconds%s\n", actual_time, end_of_device ? " (end of device reached)" : ""); printf("queue depth: %d\n", qd); printf("operation: %s ", random_offsets ? "random" : "sequential"); if (write_pct >= 1.0) printf("write\n"); else if (write_pct == 0.0) printf("read\n"); else { printf("mixed (goal %.02f%% writes)\n", write_pct * 100); printf("random request seed: %lu\n", mix_seed); } if (random_offsets) printf("random offset seed: %lu\n", seed); if (random_range) printf("random range: %lu bytes\n", random_range * req_size); printf("request size: %lu bytes\n\n", req_size); for (i = 0; i < ndev; i++) { mbs = ((double) devs[i].count * req_size) / actual_time; mbs /= 1024 * 1024; printf("%c %s: %lu %.2f MB/s", devs[i].status, devs[i].name, devs[i].count * req_size, mbs); if (write_pct != 0.0 && write_pct < 1.0) { printf(" %02.f%% writes", 100.0 * devs[i].writes / devs[i].count); } printf("\n"); } mbs = (double) total_data / actual_time; mbs /= 1024 * 1024; printf("total: %lu %.2f MB/s", total_data, mbs); mbs = (double) (devs[max_data].count - devs[min_data].count); mbs *= req_size; mbs /= actual_time; mbs /= 1024 * 1024; printf(" skew %.2f MB/s", mbs); if (write_pct != 0.0 && write_pct < 1.0) printf(" %02.f%% writes", 100.0 * total_writes / total_count); printf("\n"); return 0; }
/* * append to the end of a file using AIO DIRECT. */ void aiodio_append(char *filename) { int fd; void *bufptr; int i; int w; struct iocb iocb_array[NUM_AIO]; struct iocb *iocbs[NUM_AIO]; off_t offset = 0; io_context_t myctx; struct io_event event; struct timespec timeout; fd = open(filename, O_DIRECT|O_WRONLY|O_CREAT, 0666); if (fd < 0) { perror("cannot create file"); return; } memset(&myctx, 0, sizeof(myctx)); io_queue_init(NUM_AIO, &myctx); for (i = 0; i < NUM_AIO; i++ ) { if (posix_memalign(&bufptr, 4096, AIO_SIZE)) { perror("cannot malloc aligned memory"); return; } memset(bufptr, 0, AIO_SIZE); io_prep_pwrite(&iocb_array[i], fd, bufptr, AIO_SIZE, offset); iocbs[i] = &iocb_array[i]; offset += AIO_SIZE; } /* * Start the 1st NUM_AIO requests */ if ((w = io_submit(myctx, NUM_AIO, iocbs)) < 0) { fprintf(stderr, "io_submit write returned %d\n", w); } /* * As AIO requests finish, keep issuing more AIOs. */ for (; i < 1000; i++) { int n = 0; struct iocb *iocbp; n = io_getevents(myctx, 1, 1, &event, &timeout); if (n > 0) { iocbp = (struct iocb *)event.obj; if( n > 0){ io_prep_pwrite(iocbp, fd, iocbp->u.c.buf, AIO_SIZE, offset); offset += AIO_SIZE; if ((w = io_submit(myctx, 1, &iocbp)) < 0) { fprintf(stderr, "write %d returned %d\n", i, w); } } } } }
int main(int argc, char **argv) { io_context_t ctx; struct iocb iocb; struct iocb *iocbs[1]; struct io_event event; struct stat st; char *ptr, *buf, one[PATH_MAX], two[PATH_MAX]; size_t buflen, ptrlen; long rc; int fd1, fd2; if ((argc < 2) || (strcmp(argv[1],"-h") == 0)) { printf("Usage: partial_aio_direct <filename>\n"); exit(1); } snprintf(one, sizeof(one), "%s-1", argv[1]); snprintf(two, sizeof(two), "%s-2", argv[1]); unlink(one); unlink(two); fd1 = open(one, O_CREAT|O_RDWR|O_DIRECT, 0644); if (fd1 < 0) { perror("open"); exit(1); } fd2 = open(two, O_CREAT|O_RDWR|O_DIRECT, 0644); if (fd2 < 0) { perror("open"); exit(1); } if (fstat(fd1, &st)) { perror("open"); exit(1); } if (ftruncate(fd1, st.st_blksize)) { perror("ftruncate()"); exit(1); } if (ftruncate(fd2, st.st_blksize)) { perror("ftruncate()"); exit(1); } if (ftruncate(fd1, st.st_blksize * 2)) { perror("ftruncate()"); exit(1); } if (ftruncate(fd2, st.st_blksize * 2)) { perror("ftruncate()"); exit(1); } /* assumes this is a power of two */ buflen = st.st_blksize * 2; ptrlen = st.st_blksize * 4; /* some slop */ ptr = calloc(1, ptrlen); if (ptr == NULL) { perror("calloc"); exit(1); } /* align buf to the next natural buflen alignment after ptr */ buf = align_pow2(ptr, st.st_blksize); rc = io_queue_init(100, &ctx); if (rc) { printf("queue_init: %ld\n", rc); exit(1); } io_prep_pwrite(&iocb, fd1, buf, buflen, 0); memset(ptr, 0x42, ptrlen); printf("saw block size %lu, writing with buflen %lu\n", st.st_blksize, buflen); iocbs[0] = &iocb; rc = io_submit(ctx, 1, iocbs); if (rc != 1) { printf("submit: %ld\n", rc); exit(1); } rc = io_getevents(ctx, 1, 1, &event, NULL); printf("got %ld: data %p iocb %p res %ld res2 %ld\n", rc, event.data, event.obj, event.res, event.res2); return 0; }
static void *aio_in_thread (void *param) { char *name = (char *) param; int status; io_context_t ctx = 0; struct iocb *queue, *iocb; unsigned i; status = source_open (name); if (status < 0) return 0; source_fd = status; pthread_cleanup_push (close_fd, &source_fd); /* initialize i/o queue */ status = io_setup (aio_in, &ctx); if (status < 0) { perror ("aio_in_thread, io_setup"); return 0; } pthread_cleanup_push (queue_release, &ctx); if (aio_in == 0) aio_in = 1; queue = alloca (aio_in * sizeof *iocb); /* populate and (re)run the queue */ for (i = 0, iocb = queue; i < aio_in; i++, iocb++) { char *buf = malloc (iosize); if (!buf) { fprintf(stderr, "%s can't get buffer[%d]\n", __FUNCTION__, i); return 0; } /* host receives the data we're writing */ io_prep_pwrite (iocb, source_fd, buf, fill_in_buf (buf, iosize), 0); io_set_callback (iocb, in_complete); iocb->key = USB_DIR_IN; status = io_submit (ctx, 1, &iocb); if (status < 0) { perror (__FUNCTION__); break; } aio_in_pending++; if (verbose > 2) fprintf(stderr, "%s submit uiocb %p\n", __FUNCTION__, iocb); } status = io_run (ctx, &aio_in_pending); if (status < 0) perror ("aio_in_thread, io_run"); /* clean up */ fflush (stderr); pthread_cleanup_pop (1); pthread_cleanup_pop (1); return 0; }
static int vdev_file_io_start(zio_t *zio) { vdev_t *vd = zio->io_vd; vdev_file_t *vf = vd->vdev_tsd; #ifdef LINUX_AIO struct iocb *iocbp = &zio->io_aio; #endif ssize_t resid; int error; if (zio->io_type == ZIO_TYPE_IOCTL) { zio_vdev_io_bypass(zio); /* XXPOLICY */ if (!vdev_readable(vd)) { zio->io_error = ENXIO; return (ZIO_PIPELINE_CONTINUE); } switch (zio->io_cmd) { case DKIOCFLUSHWRITECACHE: if (zfs_nocacheflush) break; /* This doesn't actually do much with O_DIRECT... */ zio->io_error = VOP_FSYNC(vf->vf_vnode, FSYNC | FDSYNC, kcred, NULL); dprintf("fsync(%s) = %d\n", vdev_description(vd), zio->io_error); if (vd->vdev_nowritecache) { zio->io_error = ENOTSUP; break; } /* Flush the write cache */ error = flushwc(vf->vf_vnode); dprintf("flushwc(%s) = %d\n", vdev_description(vd), error); if (error) { #ifdef _KERNEL cmn_err(CE_WARN, "Failed to flush write cache " "on device '%s'. Data on pool '%s' may be lost " "if power fails. No further warnings will " "be given.", vdev_description(vd), spa_name(vd->vdev_spa)); #endif vd->vdev_nowritecache = B_TRUE; zio->io_error = error; } break; default: zio->io_error = ENOTSUP; } return (ZIO_PIPELINE_CONTINUE); } /* * In the kernel, don't bother double-caching, but in userland, * we want to test the vdev_cache code. */ if (zio->io_type == ZIO_TYPE_READ && vdev_cache_read(zio) == 0) return (ZIO_PIPELINE_STOP); if ((zio = vdev_queue_io(zio)) == NULL) return (ZIO_PIPELINE_STOP); /* XXPOLICY */ if (zio->io_type == ZIO_TYPE_WRITE) error = vdev_writeable(vd) ? vdev_error_inject(vd, zio) : ENXIO; else error = vdev_readable(vd) ? vdev_error_inject(vd, zio) : ENXIO; error = (vd->vdev_remove_wanted || vd->vdev_is_failing) ? ENXIO : error; if (error) { zio->io_error = error; zio_interrupt(zio); return (ZIO_PIPELINE_STOP); } #ifdef LINUX_AIO if (zio->io_aio_ctx && zio->io_aio_ctx->zac_enabled) { if (zio->io_type == ZIO_TYPE_READ) io_prep_pread(&zio->io_aio, vf->vf_vnode->v_fd, zio->io_data, zio->io_size, zio->io_offset); else io_prep_pwrite(&zio->io_aio, vf->vf_vnode->v_fd, zio->io_data, zio->io_size, zio->io_offset); zio->io_aio.data = zio; do { error = io_submit(zio->io_aio_ctx->zac_ctx, 1, &iocbp); } while (error == -EINTR); if (error < 0) { zio->io_error = -error; zio_interrupt(zio); } else VERIFY(error == 1); return (ZIO_PIPELINE_STOP); } #endif zio->io_error = vn_rdwr(zio->io_type == ZIO_TYPE_READ ? UIO_READ : UIO_WRITE, vf->vf_vnode, zio->io_data, zio->io_size, zio->io_offset, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, &resid); if (resid != 0 && zio->io_error == 0) zio->io_error = ENOSPC; zio_interrupt(zio); return (ZIO_PIPELINE_STOP); }
int main(int argc, char * argv[]) { int sg_fd, k, ok; unsigned char inqCmdBlk [INQ_CMD_LEN] = {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}; unsigned char turCmdBlk [TUR_CMD_LEN] = {0x00, 0, 0, 0, 0, 0}; unsigned char inqBuff[INQ_REPLY_LEN]; sg_io_hdr_t io_hdr; char * file_name = 0; char ebuff[EBUFF_SZ]; unsigned char sense_buffer[32]; int do_extra = 0; for (k = 1; k < argc; ++k) { if (0 == memcmp("-x", argv[k], 2)) do_extra = 1; else if (*argv[k] == '-') { printf("Unrecognized switch: %s\n", argv[k]); file_name = 0; break; } else if (0 == file_name) file_name = argv[k]; else { printf("too many arguments\n"); file_name = 0; break; } } if (0 == file_name) { printf("Usage: 'sg_simple_aio [-x] <sg_device>'\n"); return 1; } /* An access mode of O_RDWR is required for write()/read() interface */ if ((sg_fd = open(file_name, O_RDWR)) < 0) { snprintf(ebuff, EBUFF_SZ, "sg_simple_aio: error opening file: %s", file_name); perror(ebuff); return 1; } /* Just to be safe, check we have a new sg device by trying an ioctl */ if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) { printf("sg_simple_aio: %s doesn't seem to be an new sg device\n", file_name); close(sg_fd); return 1; } /* Prepare INQUIRY command */ memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(inqCmdBlk); /* io_hdr.iovec_count = 0; */ /* memset takes care of this */ io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; io_hdr.dxfer_len = INQ_REPLY_LEN; io_hdr.dxferp = inqBuff; io_hdr.cmdp = inqCmdBlk; io_hdr.sbp = sense_buffer; io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ /* io_hdr.flags = 0; */ /* take defaults: indirect IO, etc */ /* io_hdr.pack_id = 0; */ /* io_hdr.usr_ptr = NULL; */ #if 1 { struct iocb a_iocb; struct iocb * iocb_arr[1]; io_context_t io_ctx; int res; if (0 != (res = io_queue_init(1, &io_ctx))) { printf("io_queue_init: failed %s\n", strerror(-res)); close(sg_fd); return 1; } iocb_arr[0] = &a_iocb; io_prep_pwrite(iocb_arr[0], sg_fd, &io_hdr, sizeof(io_hdr), 0); io_set_callback(iocb_arr[0], my_io_callback); res = io_submit(io_ctx, 1, iocb_arr); if (1 != res) { printf("io_submit: returned %d\n", res); close(sg_fd); return 1; } } #else if (write(sg_fd, &io_hdr, sizeof(io_hdr)) < 0) { perror("sg_simple_aio: Inquiry write error"); close(sg_fd); return 1; } #endif /* sleep(3); */ if (read(sg_fd, &io_hdr, sizeof(io_hdr)) < 0) { perror("sg_simple_aio: Inquiry read error"); close(sg_fd); return 1; } /* now for the error processing */ ok = 0; switch (sg_err_category3(&io_hdr)) { case SG_LIB_CAT_CLEAN: ok = 1; break; case SG_LIB_CAT_RECOVERED: printf("Recovered error on INQUIRY, continuing\n"); ok = 1; break; default: /* won't bother decoding other categories */ sg_chk_n_print3("INQUIRY command error", &io_hdr); break; } if (ok) { /* output result if it is available */ char * p = (char *)inqBuff; int f = (int)*(p + 7); printf("Some of the INQUIRY command's results:\n"); printf(" %.8s %.16s %.4s ", p + 8, p + 16, p + 32); printf("[wide=%d sync=%d cmdque=%d sftre=%d]\n", !!(f & 0x20), !!(f & 0x10), !!(f & 2), !!(f & 1)); /* Extra info, not necessary to look at */ if (do_extra) printf("INQUIRY duration=%u millisecs, resid=%d, msg_status=%d\n", io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status); } /* Prepare TEST UNIT READY command */ memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(turCmdBlk); io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_NONE; io_hdr.cmdp = turCmdBlk; io_hdr.sbp = sense_buffer; io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { perror("sg_simple_aio: Test Unit Ready SG_IO ioctl error"); close(sg_fd); return 1; } /* now for the error processing */ ok = 0; switch (sg_err_category3(&io_hdr)) { case SG_LIB_CAT_CLEAN: ok = 1; break; case SG_LIB_CAT_RECOVERED: printf("Recovered error on Test Unit Ready, continuing\n"); ok = 1; break; default: /* won't bother decoding other categories */ sg_chk_n_print3("Test Unit Ready command error", &io_hdr); break; } if (ok) printf("Test Unit Ready successful so unit is ready!\n"); else printf("Test Unit Ready failed so unit may _not_ be ready!\n"); if (do_extra) printf("TEST UNIT READY duration=%u millisecs, resid=%d, msg_status=%d\n", io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status); close(sg_fd); return 0; }