/* * stress_aio_linux * stress asynchronous I/O using the linux specific aio ABI */ int stress_aio_linux( uint64_t *const counter, const uint32_t instance, const uint64_t max_ops, const char *name) { int fd, rc = EXIT_FAILURE; char filename[PATH_MAX]; const pid_t pid = getpid(); aio_context_t ctx = 0; if (!set_aio_linux_requests) { if (opt_flags & OPT_FLAGS_MAXIMIZE) opt_aio_linux_requests = MAX_AIO_REQUESTS; if (opt_flags & OPT_FLAGS_MINIMIZE) opt_aio_linux_requests = MIN_AIO_REQUESTS; } if (sys_io_setup(opt_aio_linux_requests, &ctx) < 0) { pr_failed_err(name, "io_setup"); return EXIT_FAILURE; } if (stress_temp_dir_mk(name, pid, instance) < 0) { return EXIT_FAILURE; } (void)stress_temp_filename(filename, sizeof(filename), name, pid, instance, mwc32()); (void)umask(0077); if ((fd = open(filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0) { pr_failed_err(name, "open"); goto finish; } (void)unlink(filename); do { struct iocb cb[opt_aio_linux_requests]; struct iocb *cbs[opt_aio_linux_requests]; struct io_event events[opt_aio_linux_requests]; uint8_t buffers[opt_aio_linux_requests][BUFFER_SZ]; int ret, i; long n; for (i = 0; i < opt_aio_linux_requests; i++) aio_linux_fill_buffer(i, buffers[i], BUFFER_SZ); memset(cb, 0, sizeof(cb)); for (i = 0; i < opt_aio_linux_requests; i++) { cb[i].aio_fildes = fd; cb[i].aio_lio_opcode = IOCB_CMD_PWRITE; cb[i].aio_buf = (long)buffers[i]; cb[i].aio_offset = mwc16() * BUFFER_SZ; cb[i].aio_nbytes = BUFFER_SZ; cbs[i] = &cb[i]; } ret = sys_io_submit(ctx, opt_aio_linux_requests, cbs); if (ret < 0) { if (errno == EAGAIN) continue; pr_failed_err(name, "io_submit"); break; } n = opt_aio_linux_requests; do { struct timespec timeout, *timeout_ptr; if (clock_gettime(CLOCK_REALTIME, &timeout) < 0) { timeout_ptr = NULL; } else { timeout.tv_nsec += 1000000; if (timeout.tv_nsec > 1000000000) { timeout.tv_nsec -= 1000000000; timeout.tv_sec++; } timeout_ptr = &timeout; } ret = sys_io_getevents(ctx, 1, n, events, timeout_ptr); if (ret < 0) { if ((errno == EINTR) && (opt_do_run)) continue; pr_failed_err(name, "io_getevents"); break; } else { n -= ret; } } while ((n > 0) && opt_do_run); (*counter)++; } while (opt_do_run && (!max_ops || *counter < max_ops)); rc = EXIT_SUCCESS; (void)close(fd); finish: (void)sys_io_destroy(ctx); (void)stress_temp_dir_rm(name, pid, instance); return rc; }
/* * stress_aiol * stress asynchronous I/O using the linux specific aio ABI */ static int stress_aiol(const args_t *args) { int fd, ret, rc = EXIT_FAILURE; char filename[PATH_MAX]; char buf[64]; io_context_t ctx = 0; uint64_t aio_linux_requests = DEFAULT_AIO_LINUX_REQUESTS; uint8_t *buffer; uint64_t aio_max_nr = DEFAULT_AIO_MAX_NR; if (!get_setting("aiol-requests", &aio_linux_requests)) { if (g_opt_flags & OPT_FLAGS_MAXIMIZE) aio_linux_requests = MAX_AIO_REQUESTS; if (g_opt_flags & OPT_FLAGS_MINIMIZE) aio_linux_requests = MIN_AIO_REQUESTS; } if ((aio_linux_requests < MIN_AIO_REQUESTS) || (aio_linux_requests > MAX_AIO_REQUESTS)) { pr_err("%s: iol_requests out of range", args->name); return EXIT_FAILURE; } ret = system_read("/proc/sys/fs/aio-max-nr", buf, sizeof(buf)); if (ret > 0) { if (sscanf(buf, "%" SCNu64, &aio_max_nr) != 1) { /* Guess max */ aio_max_nr = DEFAULT_AIO_MAX_NR; } } else { /* Guess max */ aio_max_nr = DEFAULT_AIO_MAX_NR; } aio_max_nr /= (args->num_instances == 0) ? 1 : args->num_instances; if (aio_max_nr < 1) aio_max_nr = 1; if (aio_linux_requests > aio_max_nr) { aio_linux_requests = aio_max_nr; if (args->instance == 0) pr_inf("%s: Limiting AIO requests to " "%" PRIu64 " per stressor (avoids running out of resources)\n", args->name, aio_linux_requests); } ret = posix_memalign((void **)&buffer, 4096, aio_linux_requests * BUFFER_SZ); if (ret) { pr_inf("%s: Out of memory allocating buffers, errno=%d (%s)", args->name, errno, strerror(errno)); return EXIT_NO_RESOURCE; } ret = io_setup(aio_linux_requests, &ctx); if (ret < 0) { /* * The libaio interface returns -errno in the * return value, so set errno accordingly */ errno = -ret; if ((errno == EAGAIN) || (errno == EACCES)) { pr_err("%s: io_setup failed, ran out of " "available events, consider increasing " "/proc/sys/fs/aio-max-nr, errno=%d (%s)\n", args->name, errno, strerror(errno)); rc = EXIT_NO_RESOURCE; goto free_buffer; } else if (errno == ENOMEM) { pr_err("%s: io_setup failed, ran out of " "memory, errno=%d (%s)\n", args->name, errno, strerror(errno)); rc = EXIT_NO_RESOURCE; goto free_buffer; } else if (errno == ENOSYS) { pr_err("%s: io_setup failed, no io_setup " "system call with this kernel, " "errno=%d (%s)\n", args->name, errno, strerror(errno)); rc = EXIT_NO_RESOURCE; goto free_buffer; } else { pr_fail_err("io_setup"); rc = EXIT_FAILURE; goto free_buffer; } } ret = stress_temp_dir_mk_args(args); if (ret < 0) { rc = exit_status(-ret); goto free_buffer; } (void)stress_temp_filename_args(args, filename, sizeof(filename), mwc32()); if ((fd = open(filename, O_CREAT | O_RDWR | O_DIRECT, S_IRUSR | S_IWUSR)) < 0) { rc = exit_status(errno); pr_fail_err("open"); goto finish; } (void)unlink(filename); do { struct iocb cb[aio_linux_requests]; struct iocb *cbs[aio_linux_requests]; struct io_event events[aio_linux_requests]; uint8_t *buffers[aio_linux_requests]; uint8_t *bufptr = buffer; uint64_t i; long n; for (i = 0; i < aio_linux_requests; i++, bufptr += BUFFER_SZ) { buffers[i] = bufptr; aio_linux_fill_buffer(i, buffers[i], BUFFER_SZ); } (void)memset(cb, 0, sizeof(cb)); for (i = 0; i < aio_linux_requests; i++) { cb[i].aio_fildes = fd; cb[i].aio_lio_opcode = IO_CMD_PWRITE; cb[i].u.c.buf = buffers[i]; cb[i].u.c.offset = mwc16() * BUFFER_SZ; cb[i].u.c.nbytes = BUFFER_SZ; cbs[i] = &cb[i]; } ret = io_submit(ctx, (long)aio_linux_requests, cbs); if (ret < 0) { errno = -ret; if (errno == EAGAIN) continue; pr_fail_err("io_submit"); break; } n = aio_linux_requests; do { struct timespec timeout, *timeout_ptr; if (clock_gettime(CLOCK_REALTIME, &timeout) < 0) { timeout_ptr = NULL; } else { timeout.tv_nsec += 1000000; if (timeout.tv_nsec > 1000000000) { timeout.tv_nsec -= 1000000000; timeout.tv_sec++; } timeout_ptr = &timeout; } ret = io_getevents(ctx, 1, n, events, timeout_ptr); if (ret < 0) { errno = -ret; if (errno == EINTR) { if (g_keep_stressing_flag) continue; else break; } pr_fail_err("io_getevents"); break; } else { n -= ret; } } while ((n > 0) && g_keep_stressing_flag); inc_counter(args); } while (keep_stressing()); rc = EXIT_SUCCESS; (void)close(fd); finish: (void)io_destroy(ctx); (void)stress_temp_dir_rm_args(args); free_buffer: free(buffer); return rc; }