| From 453b1627d3ba2541845e223a1512933e007470c8 Mon Sep 17 00:00:00 2001 |
| From: Juan Casse <jcasse@chromium.org> |
| Date: Sun, 15 Sep 2013 16:47:59 -0700 |
| Subject: [PATCH V3] Adds verify_only option |
| |
| When this option is set, a dry run (no actual io is performed) of the |
| workload will be done in order to compute the numberio for each block |
| header without overwriting the data on disk. Then, do_verify() will be |
| effectively verifying data that was written in a previous fio run. |
| In the case that "loops" is set to more than 1, do_verify() will delay |
| the verification of numberio to the last iteration when the same |
| numberio state that would have been written to disk in a previous |
| fio run has been reached. |
| |
| Signed-off-by: Juan Casse <jcasse@chromium.org> |
| Reviewed-by: Grant Grundler <grundler@chromium.org> |
| --- |
| This patch depends on "[PATCH] Adds check for numberio during verify phase" |
| sent on September 5, 2013. |
| |
| HOWTO | 11 ++++++++++- |
| README | 2 ++ |
| backend.c | 43 ++++++++++++++++++++++++++++++++++++++++++- |
| init.c | 17 +++++++++++++++++ |
| options.c | 9 +++++++++ |
| thread_options.h | 2 ++ |
| verify.c | 8 ++++++-- |
| 7 files changed, 88 insertions(+), 4 deletions(-) |
| |
| diff --git a/HOWTO b/HOWTO |
| index 005dac2..a3ca770 100644 |
| --- a/HOWTO |
| +++ b/HOWTO |
| @@ -1039,6 +1039,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. |
| |
| @@ -1077,7 +1084,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/README b/README |
| index 15a0731..7942069 100644 |
| --- a/README |
| +++ b/README |
| @@ -141,6 +141,8 @@ $ fio |
| --latency-log Generate per-job latency logs |
| --bandwidth-log Generate per-job bandwidth logs |
| --minimal Minimal (terse) output |
| + --verifyonly Skip workload io and only verify data |
| + (includes stale data check) |
| --output-format=type Output format (terse,json,normal) |
| --terse-version=type Terse version output format (default 3, or 2 or 4). |
| --version Print version info and exit |
| diff --git a/backend.c b/backend.c |
| index b9c1c12..c74c001 100644 |
| --- a/backend.c |
| +++ b/backend.c |
| @@ -1104,6 +1104,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. |
| */ |
| @@ -1311,7 +1349,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/init.c b/init.c |
| index 1afc341..34d1f14 100644 |
| --- a/init.c |
| +++ b/init.c |
| @@ -60,6 +60,8 @@ int write_bw_log = 0; |
| int read_only = 0; |
| int status_interval = 0; |
| |
| +int verify_only = 0; |
| + |
| static int write_lat_log; |
| |
| static int prev_group_jobs; |
| @@ -139,6 +141,11 @@ static struct option l_opts[FIO_NR_OPTIONS] = { |
| .val = 'r' | FIO_CLIENT_FLAG, |
| }, |
| { |
| + .name = (char *) "verifyonly", |
| + .has_arg = no_argument, |
| + .val = 'y' | FIO_CLIENT_FLAG, |
| + }, |
| + { |
| .name = (char *) "eta", |
| .has_arg = required_argument, |
| .val = 'e' | FIO_CLIENT_FLAG, |
| @@ -928,6 +935,13 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num, |
| int numjobs, file_alloced; |
| struct thread_options *o = &td->o; |
| |
| + /* |
| + * Ensure job option verify_only is set when provided as a |
| + * command-line argument. |
| + */ |
| + if (verify_only) |
| + o->verify_only = 1; |
| + |
| /* |
| * the def_thread is just for options, it's not a real job |
| */ |
| @@ -1661,6 +1675,9 @@ int parse_cmd_line(int argc, char *argv[], int client_type) |
| case 'r': |
| read_only = 1; |
| break; |
| + case 'y': |
| + verify_only = 1; |
| + break; |
| case 'v': |
| if (!cur_client) { |
| log_info("%s\n", fio_version_string); |
| diff --git a/options.c b/options.c |
| index caf89d3..e6b9ec9 100644 |
| --- a/options.c |
| +++ b/options.c |
| @@ -1935,6 +1935,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 3f345c5..c9660b4 100644 |
| --- a/thread_options.h |
| +++ b/thread_options.h |
| @@ -107,6 +107,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 63def12..9343ab9 100644 |
| --- a/verify.c |
| +++ b/verify.c |
| @@ -373,10 +373,14 @@ static int verify_io_u_meta(struct verify_header *hdr, struct vcont *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 (vh->numberio != io_u->numberio) |
| - ret = EILSEQ; |
| + if (!td->o.verify_only || td->o.loops == 0) |
| + if (vh->numberio != io_u->numberio) |
| + ret = EILSEQ; |
| |
| if (!ret) |
| return 0; |
| -- |
| 1.7.12.4 |
| |