static int verify_io_u_meta(struct verify_header *hdr, struct vcont *vc) { struct thread_data *td = vc->td; struct vhdr_meta *vh = hdr_priv(hdr); struct io_u *io_u = vc->io_u; int ret = EILSEQ; dprint(FD_VERIFY, "meta verify io_u %p, len %u\n", io_u, hdr->len); if (vh->offset == io_u->offset + vc->hdr_num * td->o.verify_interval) ret = 0; if (td->o.verify_pattern_bytes) ret |= verify_io_u_pattern(hdr, vc); /* * For read-only workloads, the program cannot be certain of the * last numberio written to a block. Checking of numberio will be * done only for workloads that write data. For verify_only, * numberio will be checked in the last iteration when the correct * state of numberio, that would have been written to each block * in a previous run of fio, has been reached. */ if ((td_write(td) || td_rw(td)) && (td_min_bs(td) == td_max_bs(td)) && !td->o.time_based) if (!td->o.verify_only || td->o.loops == 0) if (vh->numberio != io_u->numberio) ret = EILSEQ; if (!ret) return 0; vc->name = "meta"; log_verify_failure(hdr, vc); return ret; }
/* * Lazy way of fixing up options that depend on each other. We could also * define option callback handlers, but this is easier. */ static int fixup_options(struct thread_data *td) { struct thread_options *o = &td->o; int ret = 0; #ifndef FIO_HAVE_PSHARED_MUTEX if (!o->use_thread) { log_info("fio: this platform does not support process shared" " mutexes, forcing use of threads. Use the 'thread'" " option to get rid of this warning.\n"); o->use_thread = 1; ret = warnings_fatal; } #endif if (o->write_iolog_file && o->read_iolog_file) { log_err("fio: read iolog overrides write_iolog\n"); free(o->write_iolog_file); o->write_iolog_file = NULL; ret = warnings_fatal; } /* * only really works with 1 file */ if (o->zone_size && o->open_files > 1) o->zone_size = 0; /* * If zone_range isn't specified, backward compatibility dictates it * should be made equal to zone_size. */ if (o->zone_size && !o->zone_range) o->zone_range = o->zone_size; /* * Reads can do overwrites, we always need to pre-create the file */ if (td_read(td) || td_rw(td)) o->overwrite = 1; if (!o->min_bs[DDIR_READ]) o->min_bs[DDIR_READ] = o->bs[DDIR_READ]; if (!o->max_bs[DDIR_READ]) o->max_bs[DDIR_READ] = o->bs[DDIR_READ]; if (!o->min_bs[DDIR_WRITE]) o->min_bs[DDIR_WRITE] = o->bs[DDIR_WRITE]; if (!o->max_bs[DDIR_WRITE]) o->max_bs[DDIR_WRITE] = o->bs[DDIR_WRITE]; if (!o->min_bs[DDIR_TRIM]) o->min_bs[DDIR_TRIM] = o->bs[DDIR_TRIM]; if (!o->max_bs[DDIR_TRIM]) o->max_bs[DDIR_TRIM] = o->bs[DDIR_TRIM]; o->rw_min_bs = min(o->min_bs[DDIR_READ], o->min_bs[DDIR_WRITE]); o->rw_min_bs = min(o->min_bs[DDIR_TRIM], o->rw_min_bs); /* * For random IO, allow blockalign offset other than min_bs. */ if (!o->ba[DDIR_READ] || !td_random(td)) o->ba[DDIR_READ] = o->min_bs[DDIR_READ]; if (!o->ba[DDIR_WRITE] || !td_random(td)) o->ba[DDIR_WRITE] = o->min_bs[DDIR_WRITE]; if (!o->ba[DDIR_TRIM] || !td_random(td)) o->ba[DDIR_TRIM] = o->min_bs[DDIR_TRIM]; if ((o->ba[DDIR_READ] != o->min_bs[DDIR_READ] || o->ba[DDIR_WRITE] != o->min_bs[DDIR_WRITE] || o->ba[DDIR_TRIM] != o->min_bs[DDIR_TRIM]) && !o->norandommap) { log_err("fio: Any use of blockalign= turns off randommap\n"); o->norandommap = 1; ret = warnings_fatal; } if (!o->file_size_high) o->file_size_high = o->file_size_low; if (o->start_delay_high) o->start_delay = get_rand_start_delay(td); if (o->norandommap && o->verify != VERIFY_NONE && !fixed_block_size(o)) { log_err("fio: norandommap given for variable block sizes, " "verify disabled\n"); o->verify = VERIFY_NONE; ret = warnings_fatal; } if (o->bs_unaligned && (o->odirect || td->io_ops->flags & FIO_RAWIO)) log_err("fio: bs_unaligned may not work with raw io\n"); /* * thinktime_spin must be less than thinktime */ if (o->thinktime_spin > o->thinktime) o->thinktime_spin = o->thinktime; /* * The low water mark cannot be bigger than the iodepth */ if (o->iodepth_low > o->iodepth || !o->iodepth_low) o->iodepth_low = o->iodepth; /* * If batch number isn't set, default to the same as iodepth */ if (o->iodepth_batch > o->iodepth || !o->iodepth_batch) o->iodepth_batch = o->iodepth; if (o->nr_files > td->files_index) o->nr_files = td->files_index; if (o->open_files > o->nr_files || !o->open_files) o->open_files = o->nr_files; if (((o->rate[DDIR_READ] + o->rate[DDIR_WRITE] + o->rate[DDIR_TRIM]) && (o->rate_iops[DDIR_READ] + o->rate_iops[DDIR_WRITE] + o->rate_iops[DDIR_TRIM])) || ((o->ratemin[DDIR_READ] + o->ratemin[DDIR_WRITE] + o->ratemin[DDIR_TRIM]) && (o->rate_iops_min[DDIR_READ] + o->rate_iops_min[DDIR_WRITE] + o->rate_iops_min[DDIR_TRIM]))) { log_err("fio: rate and rate_iops are mutually exclusive\n"); ret = 1; } if ((o->rate[DDIR_READ] < o->ratemin[DDIR_READ]) || (o->rate[DDIR_WRITE] < o->ratemin[DDIR_WRITE]) || (o->rate[DDIR_TRIM] < o->ratemin[DDIR_TRIM]) || (o->rate_iops[DDIR_READ] < o->rate_iops_min[DDIR_READ]) || (o->rate_iops[DDIR_WRITE] < o->rate_iops_min[DDIR_WRITE]) || (o->rate_iops[DDIR_TRIM] < o->rate_iops_min[DDIR_TRIM])) { log_err("fio: minimum rate exceeds rate\n"); ret = 1; } if (!o->timeout && o->time_based) { log_err("fio: time_based requires a runtime/timeout setting\n"); o->time_based = 0; ret = warnings_fatal; } if (o->fill_device && !o->size) o->size = -1ULL; if (o->verify != VERIFY_NONE) { if (td_write(td) && o->do_verify && o->numjobs > 1) { log_info("Multiple writers may overwrite blocks that " "belong to other jobs. This can cause " "verification failures.\n"); ret = warnings_fatal; } o->refill_buffers = 1; if (o->max_bs[DDIR_WRITE] != o->min_bs[DDIR_WRITE] && !o->verify_interval) o->verify_interval = o->min_bs[DDIR_WRITE]; } if (o->pre_read) { o->invalidate_cache = 0; if (td->io_ops->flags & FIO_PIPEIO) { log_info("fio: cannot pre-read files with an IO engine" " that isn't seekable. Pre-read disabled.\n"); ret = warnings_fatal; } } if (!o->unit_base) { if (td->io_ops->flags & FIO_BIT_BASED) o->unit_base = 1; else o->unit_base = 8; } #ifndef CONFIG_FDATASYNC if (o->fdatasync_blocks) { log_info("fio: this platform does not support fdatasync()" " falling back to using fsync(). Use the 'fsync'" " option instead of 'fdatasync' to get rid of" " this warning\n"); o->fsync_blocks = o->fdatasync_blocks; o->fdatasync_blocks = 0; ret = warnings_fatal; } #endif #ifdef WIN32 /* * Windows doesn't support O_DIRECT or O_SYNC with the _open interface, * so fail if we're passed those flags */ if ((td->io_ops->flags & FIO_SYNCIO) && (td->o.odirect || td->o.sync_io)) { log_err("fio: Windows does not support direct or non-buffered io with" " the synchronous ioengines. Use the 'windowsaio' ioengine" " with 'direct=1' and 'iodepth=1' instead.\n"); ret = 1; } #endif /* * For fully compressible data, just zero them at init time. * It's faster than repeatedly filling it. */ if (td->o.compress_percentage == 100) { td->o.zero_buffers = 1; td->o.compress_percentage = 0; } /* * Using a non-uniform random distribution excludes usage of * a random map */ if (td->o.random_distribution != FIO_RAND_DIST_RANDOM) td->o.norandommap = 1; /* * If size is set but less than the min block size, complain */ if (o->size && o->size < td_min_bs(td)) { log_err("fio: size too small, must be larger than the IO size: %llu\n", (unsigned long long) o->size); ret = 1; } /* * O_ATOMIC implies O_DIRECT */ if (td->o.oatomic) td->o.odirect = 1; /* * If randseed is set, that overrides randrepeat */ if (td->o.rand_seed) td->o.rand_repeatable = 0; if ((td->io_ops->flags & FIO_NOEXTEND) && td->o.file_append) { log_err("fio: can't append/extent with IO engine %s\n", td->io_ops->name); ret = 1; } return ret; }
static int verify_header(struct io_u *io_u, struct thread_data *td, struct verify_header *hdr, unsigned int hdr_num, unsigned int hdr_len) { void *p = hdr; uint32_t crc; if (hdr->magic != FIO_HDR_MAGIC) { log_err("verify: bad magic header %x, wanted %x", hdr->magic, FIO_HDR_MAGIC); goto err; } if (hdr->len != hdr_len) { log_err("verify: bad header length %u, wanted %u", hdr->len, hdr_len); goto err; } if (hdr->rand_seed != io_u->rand_seed) { log_err("verify: bad header rand_seed %"PRIu64 ", wanted %"PRIu64, hdr->rand_seed, io_u->rand_seed); goto err; } if (hdr->offset != io_u->offset + hdr_num * td->o.verify_interval) { log_err("verify: bad header offset %"PRIu64 ", wanted %llu", hdr->offset, io_u->offset); goto err; } /* * For read-only workloads, the program cannot be certain of the * last numberio written to a block. Checking of numberio will be * done only for workloads that write data. For verify_only, * numberio will be checked in the last iteration when the correct * state of numberio, that would have been written to each block * in a previous run of fio, has been reached. */ if ((td_write(td) || td_rw(td)) && (td_min_bs(td) == td_max_bs(td)) && !td->o.time_based) if (!td->o.verify_only || td->o.loops == 0) if (hdr->numberio != io_u->numberio) { log_err("verify: bad header numberio %"PRIu16 ", wanted %"PRIu16, hdr->numberio, io_u->numberio); goto err; } crc = fio_crc32c(p, offsetof(struct verify_header, crc32)); if (crc != hdr->crc32) { log_err("verify: bad header crc %x, calculated %x", hdr->crc32, crc); goto err; } return 0; err: log_err(" at file %s offset %llu, length %u\n", io_u->file->file_name, io_u->offset + hdr_num * hdr_len, hdr_len); if (td->o.verify_dump) dump_buf(p, hdr_len, io_u->offset + hdr_num * hdr_len, "hdr_fail", io_u->file); return EILSEQ; }
/* * Load a blktrace file by reading all the blk_io_trace entries, and storing * them as io_pieces like the fio text version would do. */ int load_blktrace(struct thread_data *td, const char *filename, int need_swap) { struct blk_io_trace t; unsigned long ios[DDIR_RWDIR_CNT], skipped_writes; unsigned int rw_bs[DDIR_RWDIR_CNT]; struct fifo *fifo; int fd, i, old_state; struct fio_file *f; int this_depth[DDIR_RWDIR_CNT], depth[DDIR_RWDIR_CNT], max_depth; fd = open(filename, O_RDONLY); if (fd < 0) { td_verror(td, errno, "open blktrace file"); return 1; } fifo = fifo_alloc(TRACE_FIFO_SIZE); old_state = td_bump_runstate(td, TD_SETTING_UP); td->o.size = 0; for (i = 0; i < DDIR_RWDIR_CNT; i++) { ios[i] = 0; rw_bs[i] = 0; this_depth[i] = 0; depth[i] = 0; } skipped_writes = 0; do { int ret = trace_fifo_get(td, fifo, fd, &t, sizeof(t)); if (ret < 0) goto err; else if (!ret) break; else if (ret < (int) sizeof(t)) { log_err("fio: short fifo get\n"); break; } if (need_swap) byteswap_trace(&t); if ((t.magic & 0xffffff00) != BLK_IO_TRACE_MAGIC) { log_err("fio: bad magic in blktrace data: %x\n", t.magic); goto err; } if ((t.magic & 0xff) != BLK_IO_TRACE_VERSION) { log_err("fio: bad blktrace version %d\n", t.magic & 0xff); goto err; } ret = discard_pdu(td, fifo, fd, &t); if (ret < 0) { td_verror(td, ret, "blktrace lseek"); goto err; } else if (t.pdu_len != ret) { log_err("fio: discarded %d of %d\n", ret, t.pdu_len); goto err; } if ((t.action & BLK_TC_ACT(BLK_TC_NOTIFY)) == 0) { if ((t.action & 0xffff) == __BLK_TA_QUEUE) depth_inc(&t, this_depth); else if (((t.action & 0xffff) == __BLK_TA_BACKMERGE) || ((t.action & 0xffff) == __BLK_TA_FRONTMERGE)) depth_dec(&t, this_depth); else if ((t.action & 0xffff) == __BLK_TA_COMPLETE) depth_end(&t, this_depth, depth); if (t_is_write(&t) && read_only) { skipped_writes++; continue; } } handle_trace(td, &t, ios, rw_bs); } while (1); for (i = 0; i < td->files_index; i++) { f = td->files[i]; trace_add_open_close_event(td, f->fileno, FIO_LOG_CLOSE_FILE); } fifo_free(fifo); close(fd); td_restore_runstate(td, old_state); if (!td->files_index) { log_err("fio: did not find replay device(s)\n"); return 1; } /* * For stacked devices, we don't always get a COMPLETE event so * the depth grows to insane values. Limit it to something sane(r). */ max_depth = 0; for (i = 0; i < DDIR_RWDIR_CNT; i++) { if (depth[i] > 1024) depth[i] = 1024; else if (!depth[i] && ios[i]) depth[i] = 1; max_depth = max(depth[i], max_depth); } if (skipped_writes) log_err("fio: %s skips replay of %lu writes due to read-only\n", td->o.name, skipped_writes); if (!ios[DDIR_READ] && !ios[DDIR_WRITE]) { log_err("fio: found no ios in blktrace data\n"); return 1; } else if (ios[DDIR_READ] && !ios[DDIR_WRITE]) { td->o.td_ddir = TD_DDIR_READ; td->o.max_bs[DDIR_READ] = rw_bs[DDIR_READ]; } else if (!ios[DDIR_READ] && ios[DDIR_WRITE]) { td->o.td_ddir = TD_DDIR_WRITE; td->o.max_bs[DDIR_WRITE] = rw_bs[DDIR_WRITE]; } else { td->o.td_ddir = TD_DDIR_RW; td->o.max_bs[DDIR_READ] = rw_bs[DDIR_READ]; td->o.max_bs[DDIR_WRITE] = rw_bs[DDIR_WRITE]; td->o.max_bs[DDIR_TRIM] = rw_bs[DDIR_TRIM]; } /* * We need to do direct/raw ios to the device, to avoid getting * read-ahead in our way. But only do so if the minimum block size * is a multiple of 4k, otherwise we don't know if it's safe to do so. */ if (!fio_option_is_set(&td->o, odirect) && !(td_min_bs(td) & 4095)) td->o.odirect = 1; /* * If depth wasn't manually set, use probed depth */ if (!fio_option_is_set(&td->o, iodepth)) td->o.iodepth = td->o.iodepth_low = max_depth; return 0; err: close(fd); fifo_free(fifo); return 1; }