The following changes since commit 479471c409a61d01290ac9444042357b03f8d0b0: server: make the connect code fully IPv6 (2014-01-23 20:42:06 -0800) are available in the git repository at: git://git.kernel.dk/fio.git master Jens Axboe (2): engine: more checks on IPv6 and multicast Add verify_only to man page Juan Casse (3): Adds check for numberio during verify phase. Adds verify_only option Adds check for rand_seed during verify phase. HOWTO | 11 ++++++++- backend.c | 43 ++++++++++++++++++++++++++++++++++++- engines/net.c | 8 ++++++- fio.1 | 7 ++++++ ioengine.h | 1 + iolog.c | 1 + iolog.h | 1 + libfio.c | 1 - options.c | 9 +++++++ thread_options.h | 2 + verify.c | 63 +++++++++++++++++++++++++++++++++++++++++++++-------- 11 files changed, 133 insertions(+), 14 deletions(-) --- Diff of recent changes: diff --git a/HOWTO b/HOWTO index e69cf41..9830fa1 100644 --- a/HOWTO +++ b/HOWTO @@ -1068,6 +1068,13 @@ loops=int Run the specified number of iterations of this job. Used to repeat the same workload a given number of times. Defaults to 1. +verify_only Do not perform specified workload---only verify data still + matches previous invocation of this workload. This option + allows one to check data multiple times at a later date + without overwriting it. This option makes sense only for + workloads that write data, and does not support workloads + with the time_based option set. + do_verify=bool Run the verify phase after a write phase. Only makes sense if verify is set. Defaults to 1. @@ -1106,7 +1113,9 @@ verify=str If writing to a file, fio can verify the file contents meta Write extra information about each io (timestamp, block number etc.). The block - number is verified. See also verify_pattern. + number is verified. The io sequence number is + verified for workloads that write data. + See also verify_pattern. null Only pretend to verify. Useful for testing internals with ioengine=null, not for much diff --git a/backend.c b/backend.c index c9a20a3..93e6632 100644 --- a/backend.c +++ b/backend.c @@ -1120,6 +1120,44 @@ static int exec_string(struct thread_options *o, const char *string, const char } /* + * Dry run to compute correct state of numberio for verification. + */ +static uint64_t do_dry_run(struct thread_data *td) +{ + uint64_t bytes_done[DDIR_RWDIR_CNT] = { 0, 0, 0 }; + + td_set_runstate(td, TD_RUNNING); + + while ((td->o.read_iolog_file && !flist_empty(&td->io_log_list)) || + (!flist_empty(&td->trim_list)) || !io_bytes_exceeded(td)) { + struct io_u *io_u; + int ret; + + if (td->terminate || td->done) + break; + + io_u = get_io_u(td); + if (!io_u) + break; + + io_u->flags |= IO_U_F_FLIGHT; + io_u->error = 0; + io_u->resid = 0; + if (ddir_rw(acct_ddir(io_u))) + td->io_issues[acct_ddir(io_u)]++; + if (ddir_rw(io_u->ddir)) { + io_u_mark_depth(td, 1); + td->ts.total_io_u[io_u->ddir]++; + } + + ret = io_u_sync_complete(td, io_u, bytes_done); + (void) ret; + } + + return bytes_done[DDIR_WRITE] + bytes_done[DDIR_TRIM]; +} + +/* * Entry point for the thread based jobs. The process based jobs end up * here as well, after a little setup. */ @@ -1332,7 +1370,10 @@ static void *thread_main(void *data) prune_io_piece_log(td); - verify_bytes = do_io(td); + if (td->o.verify_only && (td_write(td) || td_rw(td))) + verify_bytes = do_dry_run(td); + else + verify_bytes = do_io(td); clear_state = 1; diff --git a/engines/net.c b/engines/net.c index 5fdc88c..4be106a 100644 --- a/engines/net.c +++ b/engines/net.c @@ -1039,12 +1039,17 @@ static int fio_netio_setup_listen_inet(struct thread_data *td, short port) } #endif - if (td->o.filename){ + if (td->o.filename) { if (!is_udp(o) || !fio_netio_is_multicast(td->o.filename)) { log_err("fio: hostname not valid for non-multicast inbound network IO\n"); close(fd); return 1; } + if (is_ipv6(o)) { + log_err("fio: IPv6 not supported for multicast network IO"); + close(fd); + return 1; + } inet_aton(td->o.filename, &sin.sin_addr); @@ -1058,6 +1063,7 @@ static int fio_netio_setup_listen_inet(struct thread_data *td, short port) } else { mr.imr_interface.s_addr = htonl(INADDR_ANY); } + if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char*)&mr, sizeof(mr)) < 0) { td_verror(td, errno, "setsockopt IP_ADD_MEMBERSHIP"); close(fd); diff --git a/fio.1 b/fio.1 index b5ff80c..3cdfd27 100644 --- a/fio.1 +++ b/fio.1 @@ -934,6 +934,13 @@ Unlink job files when done. Default: false. Specifies the number of iterations (runs of the same workload) of this job. Default: 1. .TP +.BI verify_only \fR=\fPbool +Do not perform the specified workload, only verify data still matches previous +invocation of this workload. This option allows one to check data multiple +times at a later date without overwriting it. This option makes sense only for +workloads that write data, and does not support workloads with the +\fBtime_based\fR option set. +.TP .BI do_verify \fR=\fPbool Run the verify phase after a write phase. Only valid if \fBverify\fR is set. Default: true. diff --git a/ioengine.h b/ioengine.h index 6dd2aa4..949af91 100644 --- a/ioengine.h +++ b/ioengine.h @@ -50,6 +50,7 @@ struct io_u { */ unsigned long buflen; unsigned long long offset; + unsigned short numberio; void *buf; /* diff --git a/iolog.c b/iolog.c index 6593367..ec29971 100644 --- a/iolog.c +++ b/iolog.c @@ -188,6 +188,7 @@ void log_io_piece(struct thread_data *td, struct io_u *io_u) ipo->file = io_u->file; ipo->offset = io_u->offset; ipo->len = io_u->buflen; + ipo->numberio = io_u->numberio; if (io_u_should_trim(td, io_u)) { flist_add_tail(&ipo->trim_list, &td->trim_list); diff --git a/iolog.h b/iolog.h index 6503acf..321576d 100644 --- a/iolog.h +++ b/iolog.h @@ -83,6 +83,7 @@ struct io_piece { struct fio_file *file; }; unsigned long long offset; + unsigned short numberio; unsigned long len; unsigned int flags; enum fio_ddir ddir; diff --git a/libfio.c b/libfio.c index 7eb4576..222cd16 100644 --- a/libfio.c +++ b/libfio.c @@ -85,7 +85,6 @@ static void reset_io_counters(struct thread_data *td) td->this_io_blocks[ddir] = 0; td->rate_bytes[ddir] = 0; td->rate_blocks[ddir] = 0; - td->io_issues[ddir] = 0; } td->zone_bytes = 0; diff --git a/options.c b/options.c index b1b6c8e..525d318 100644 --- a/options.c +++ b/options.c @@ -2018,6 +2018,15 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .group = FIO_OPT_G_RUNTIME, }, { + .name = "verify_only", + .lname = "Verify only", + .type = FIO_OPT_STR_SET, + .off1 = td_var_offset(verify_only), + .help = "Verifies previously written data is still valid", + .category = FIO_OPT_C_GENERAL, + .group = FIO_OPT_G_RUNTIME, + }, + { .name = "ramp_time", .lname = "Ramp time", .type = FIO_OPT_STR_VAL_TIME, diff --git a/thread_options.h b/thread_options.h index f40a992..2f807cd 100644 --- a/thread_options.h +++ b/thread_options.h @@ -109,6 +109,8 @@ struct thread_options { unsigned int fsync_on_close; unsigned int bs_is_seq_rand; + unsigned int verify_only; + unsigned int random_distribution; fio_fp64_t zipf_theta; diff --git a/verify.c b/verify.c index 721aeb4..568bae8 100644 --- a/verify.c +++ b/verify.c @@ -383,6 +383,19 @@ static int verify_io_u_meta(struct verify_header *hdr, struct vcont *vc) 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)) + if (!td->o.verify_only || td->o.loops == 0) + if (vh->numberio != io_u->numberio) + ret = EILSEQ; + if (!ret) return 0; @@ -658,18 +671,17 @@ static int verify_header(struct io_u *io_u, struct verify_header *hdr) uint32_t crc; if (hdr->magic != FIO_HDR_MAGIC) - return 0; - if (hdr->len > io_u->buflen) { - log_err("fio: verify header exceeds buffer length (%u > %lu)\n", hdr->len, io_u->buflen); - return 0; - } + return 1; + if (hdr->len > io_u->buflen) + return 2; + if (hdr->rand_seed != io_u->rand_seed) + return 3; crc = fio_crc32c(p, offsetof(struct verify_header, crc32)); if (crc == hdr->crc32) - return 1; - + return 0; log_err("fio: verify header crc %x, calculated %x\n", hdr->crc32, crc); - return 0; + return 4; } int verify_io_u(struct thread_data *td, struct io_u *io_u) @@ -706,13 +718,41 @@ int verify_io_u(struct thread_data *td, struct io_u *io_u) memswp(p, p + td->o.verify_offset, header_size); hdr = p; - if (!verify_header(io_u, hdr)) { + ret = verify_header(io_u, hdr); + switch (ret) { + case 0: + break; + case 1: log_err("verify: bad magic header %x, wanted %x at " "file %s offset %llu, length %u\n", hdr->magic, FIO_HDR_MAGIC, io_u->file->file_name, io_u->offset + hdr_num * hdr->len, hdr->len); return EILSEQ; + break; + case 2: + log_err("fio: verify header exceeds buffer length (%u " + "> %lu)\n", hdr->len, io_u->buflen); + return EILSEQ; + break; + case 3: + log_err("verify: bad header rand_seed %"PRIu64 + ", wanted %"PRIu64" at file %s offset %llu, " + "length %u\n", + hdr->rand_seed, io_u->rand_seed, + io_u->file->file_name, + io_u->offset + hdr_num * hdr->len, hdr->len); + return EILSEQ; + break; + case 4: + return EILSEQ; + break; + default: + log_err("verify: unknown header error at file %s " + "offset %llu, length %u\n", + io_u->file->file_name, + io_u->offset + hdr_num * hdr->len, hdr->len); + return EILSEQ; } if (td->o.verify != VERIFY_NONE) @@ -782,7 +822,7 @@ static void fill_meta(struct verify_header *hdr, struct thread_data *td, vh->time_sec = io_u->start_time.tv_sec; vh->time_usec = io_u->start_time.tv_usec; - vh->numberio = td->io_issues[DDIR_WRITE]; + vh->numberio = io_u->numberio; vh->offset = io_u->offset + header_num * td->o.verify_interval; } @@ -956,6 +996,8 @@ void populate_verify_io_u(struct thread_data *td, struct io_u *io_u) if (td->o.verify == VERIFY_NULL) return; + io_u->numberio = td->io_issues[io_u->ddir]; + fill_pattern_headers(td, io_u, 0, 0); } @@ -988,6 +1030,7 @@ int get_next_verify(struct thread_data *td, struct io_u *io_u) io_u->offset = ipo->offset; io_u->buflen = ipo->len; + io_u->numberio = ipo->numberio; io_u->file = ipo->file; io_u->flags |= IO_U_F_VER_LIST; -- To unsubscribe from this list: send the line "unsubscribe fio" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html