-
Notifications
You must be signed in to change notification settings - Fork 1.4k
verify: add --verify_type option for crash-consistent verification #1948
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3734,6 +3734,34 @@ Recreate an instance of the \fBverify_pattern\fR every | |
| up the process of writing each block on a device with its offset. Default: | ||
| 0 (disabled). | ||
| .TP | ||
| .BI verify_type \fR=\fPstr | ||
| Controls which write operations are included during the verification phase. | ||
| This option only affects offline verification when using \fBverify_state_save\fR | ||
| to save completion state and later verify with a separate job. The allowed | ||
| values are: | ||
| .RS | ||
| .RS | ||
| .TP | ||
| .B flush | ||
| Only verify writes that completed at or before the last fsync operation. | ||
| This mode filters out writes that completed after the last fsync, which may | ||
| not be persistent on storage. Writes with the Force Unit Access (FUA) flag | ||
| are always included regardless of fsync timing, as they bypass the cache and | ||
| are immediately persistent. This is useful for testing data persistence | ||
| guarantees across power failures or system crashes. | ||
| .RE | ||
| .P | ||
| When \fBverify_type=flush\fR is used, fio tracks fsync completion times and | ||
| write completion times during the write phase. During verification, only | ||
| writes that meet the fsync timing criteria are verified. This allows testing | ||
| scenarios where only data that was properly synced before a simulated | ||
| failure should be verified. | ||
| .P | ||
| This option requires \fBverify_state_save\fR to be enabled and is only | ||
| effective during offline verification (separate verify job). Default: none | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you need to explicitly list that none as one of the options above too. |
||
| (verify all completed writes). | ||
| .RE | ||
| .TP | ||
| .BI verify_fatal \fR=\fPbool | ||
| Normally fio will keep checking the entire contents before quitting on a | ||
| block verification failure. If this option is set, fio will exit the job on | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2063,7 +2063,7 @@ static void account_io_completion(struct thread_data *td, struct io_u *io_u, | |
| } | ||
|
|
||
| static void file_log_write_comp(const struct thread_data *td, struct fio_file *f, | ||
| uint64_t offset, unsigned int bytes) | ||
| uint64_t offset, unsigned int bytes, struct io_u *io_u) | ||
| { | ||
| int idx; | ||
|
|
||
|
|
@@ -2079,11 +2079,31 @@ static void file_log_write_comp(const struct thread_data *td, struct fio_file *f | |
| return; | ||
|
|
||
| idx = f->last_write_idx++; | ||
| f->last_write_comp[idx] = offset; | ||
| f->last_write_comp[idx].offset = offset; | ||
| f->last_write_comp[idx].completion_time_nsec = ntime_since_now(&io_u->start_time); | ||
| f->last_write_comp[idx].flags = 0; | ||
| f->last_write_comp[idx].flush_count = f->flush_count; | ||
|
|
||
| /* Check if this is a FUA write */ | ||
| if (io_u && (io_u->flags & IO_U_F_FUA)) | ||
| f->last_write_comp[idx].flags |= FIO_WRITE_COMP_FUA; | ||
|
|
||
| if (f->last_write_idx == td->last_write_comp_depth) | ||
| f->last_write_idx = 0; | ||
| } | ||
|
|
||
| static void file_log_flush_comp(struct fio_file *f, struct io_u *io_u) | ||
| { | ||
| if (!f) | ||
| return; | ||
|
|
||
| /* Track the last FLUSH completion timestamp */ | ||
| f->last_flush_time_nsec = ntime_since_now(&io_u->start_time); | ||
|
|
||
| /* Increment FLUSH counter */ | ||
| f->flush_count++; | ||
| } | ||
|
|
||
| static bool should_account(struct thread_data *td) | ||
| { | ||
| return ramp_time_over(td) && (td->runstate == TD_RUNNING || | ||
|
|
@@ -2125,7 +2145,10 @@ static void io_completed(struct thread_data *td, struct io_u **io_u_ptr, | |
| if (ddir_sync(ddir)) { | ||
| if (io_u->error) | ||
| goto error; | ||
|
|
||
| /* Log flush completion */ | ||
| if (f) { | ||
| file_log_flush_comp(f, io_u); | ||
| f->first_write = -1ULL; | ||
| f->last_write = -1ULL; | ||
| } | ||
|
|
@@ -2164,7 +2187,7 @@ static void io_completed(struct thread_data *td, struct io_u **io_u_ptr, | |
| } | ||
|
|
||
| if (ddir == DDIR_WRITE) | ||
| file_log_write_comp(td, f, io_u->offset, bytes); | ||
| file_log_write_comp(td, f, io_u->offset, bytes, io_u); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we're going to pass the full io_u does it make sense to pass the offset separately rather than calculate it in the function? |
||
|
|
||
| if (should_account(td)) | ||
| account_io_completion(td, io_u, icd, ddir, bytes); | ||
|
|
@@ -2464,6 +2487,10 @@ int do_io_u_sync(const struct thread_data *td, struct io_u *io_u) | |
|
|
||
| if (ret < 0) | ||
| io_u->error = errno; | ||
| else { | ||
| /* Record FLUSH completion timing for verification state */ | ||
| file_log_flush_comp(io_u->file, io_u); | ||
| } | ||
|
|
||
| return ret; | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,14 +26,16 @@ static void show_s(struct thread_io_list *s, unsigned int no_s) | |
| printf("Max completions per file:\t\t%lu\n", (unsigned long) s->max_no_comps_per_file); | ||
| printf("Number IOs:\t%llu\n", (unsigned long long) s->numberio); | ||
| printf("Index:\t\t%llu\n", (unsigned long long) s->index); | ||
| printf("Last flush count:\t%u\n", s->last_flush_count); | ||
|
|
||
| printf("Completions:\n"); | ||
| if (!s->no_comps) | ||
| return; | ||
| for (i = s->no_comps - 1; i >= 0; i--) { | ||
| printf("\t(file=%2llu) %llu\n", | ||
| printf("\t(file=%2llu) %llu (flush_count=%u)\n", | ||
| (unsigned long long) s->comps[i].fileno, | ||
| (unsigned long long) s->comps[i].offset); | ||
| (unsigned long long) s->comps[i].offset, | ||
| s->comps[i].flush_count); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -51,10 +53,12 @@ static void show(struct thread_io_list *s, size_t size) | |
| s->nofiles = le32_to_cpu(s->nofiles); | ||
| s->numberio = le64_to_cpu(s->numberio); | ||
| s->index = le64_to_cpu(s->index); | ||
| s->last_flush_count = le32_to_cpu(s->last_flush_count); | ||
|
|
||
| for (i = 0; i < s->no_comps; i++) { | ||
| s->comps[i].fileno = le64_to_cpu(s->comps[i].fileno); | ||
| s->comps[i].offset = le64_to_cpu(s->comps[i].offset); | ||
| s->comps[i].flush_count = le32_to_cpu(s->comps[i].flush_count); | ||
| } | ||
|
|
||
| show_s(s, no_s); | ||
|
|
@@ -92,7 +96,7 @@ static void show_verify_state(void *buf, size_t size) | |
| return; | ||
| } | ||
|
|
||
| if (hdr->version == 0x04) | ||
| if (hdr->version == 0x05) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're going to need to bump this up even further after rebasing... |
||
| show(s, size); | ||
| else | ||
| log_err("Unsupported version %d\n", (int) hdr->version); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -142,6 +142,7 @@ struct thread_options { | |
| unsigned int sync_io; | ||
| unsigned int write_hint; | ||
| unsigned int verify; | ||
| unsigned int verify_type; | ||
| unsigned int do_verify; | ||
| unsigned int verify_interval; | ||
| unsigned int verify_offset; | ||
|
|
@@ -189,6 +190,7 @@ struct thread_options { | |
|
|
||
| struct zone_split *zone_split[DDIR_RWDIR_CNT]; | ||
| unsigned int zone_split_nr[DDIR_RWDIR_CNT]; | ||
| uint32_t pad2; | ||
|
|
||
| fio_fp64_t zipf_theta; | ||
| fio_fp64_t pareto_h; | ||
|
|
@@ -477,6 +479,7 @@ struct thread_options_pack { | |
| uint32_t sync_io; | ||
| uint32_t write_hint; | ||
| uint32_t verify; | ||
| uint32_t verify_type; | ||
| uint32_t do_verify; | ||
| uint32_t verify_interval; | ||
| uint32_t verify_offset; | ||
|
|
@@ -521,6 +524,7 @@ struct thread_options_pack { | |
|
|
||
| struct zone_split zone_split[DDIR_RWDIR_CNT][ZONESPLIT_MAX]; | ||
| uint32_t zone_split_nr[DDIR_RWDIR_CNT]; | ||
| uint32_t pad2; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After rebasing you'll have to see if you still need the pad. |
||
|
|
||
| fio_fp64_t zipf_theta; | ||
| fio_fp64_t pareto_h; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,6 +28,8 @@ struct thread_rand_state { | |
| struct file_comp { | ||
| uint64_t fileno; | ||
| uint64_t offset; | ||
| uint32_t flush_count; /* FLUSH count at completion time for ordering */ | ||
| uint32_t flags; /* I/O flags including FUA */ | ||
| }; | ||
|
|
||
| struct thread_io_list { | ||
|
|
@@ -37,6 +39,8 @@ struct thread_io_list { | |
| uint32_t nofiles; | ||
| uint64_t numberio; | ||
| uint64_t index; | ||
| uint32_t last_flush_count; /* Last FLUSH count for ordering */ | ||
| uint32_t padding; /* Padding for alignment */ | ||
| struct thread_rand_state rand; | ||
| uint8_t name[64]; | ||
| struct file_comp comps[0]; | ||
|
|
@@ -47,7 +51,7 @@ struct all_io_list { | |
| struct thread_io_list state[0]; | ||
| }; | ||
|
|
||
| #define VSTATE_HDR_VERSION 0x04 | ||
| #define VSTATE_HDR_VERSION 0x05 /* Incremented for FLUSH count support */ | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might need bumping after rebasing. |
||
|
|
||
| struct verify_state_hdr { | ||
| uint64_t version; | ||
|
|
@@ -57,6 +61,9 @@ struct verify_state_hdr { | |
|
|
||
| #define IO_LIST_ALL 0xffffffff | ||
|
|
||
| /* Flags for file_comp.flags */ | ||
| #define FIO_COMP_FLAG_FUA 0x1 /* Write had Force Unit Access flag */ | ||
|
|
||
| struct io_u; | ||
| extern struct all_io_list *get_all_io_list(int, size_t *); | ||
| extern void __verify_save_state(struct all_io_list *, const char *); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be hidden in the DDIR_WRITE case of fio_nvme_uring_cmd_prep() in nvme.c?