+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;
+}
+
+int verify_io_u(struct thread_data *td, struct io_u **io_u_ptr)
+{
+ struct verify_header *hdr;
+ struct io_u *io_u = *io_u_ptr;
+ unsigned int header_size, hdr_inc, hdr_num = 0;
+ void *p;
+ int ret;
+
+ if (td->o.verify == VERIFY_NULL || io_u->ddir != DDIR_READ)
+ return 0;
+ /*
+ * If the IO engine is faking IO (like null), then just pretend
+ * we verified everything.
+ */
+ if (td_ioengine_flagged(td, FIO_FAKEIO))
+ return 0;
+
+ if (io_u->flags & IO_U_F_TRIMMED) {
+ ret = verify_trimmed_io_u(td, io_u);
+ goto done;
+ }
+
+ hdr_inc = get_hdr_inc(td, io_u);
+
+ ret = 0;
+ for (p = io_u->buf; p < io_u->buf + io_u->buflen;
+ p += hdr_inc, hdr_num++) {
+ struct vcont vc = {
+ .io_u = io_u,
+ .hdr_num = hdr_num,
+ .td = td,
+ };
+ unsigned int verify_type;
+
+ if (ret && td->o.verify_fatal)
+ break;
+
+ header_size = __hdr_size(td->o.verify);
+ if (td->o.verify_offset)
+ memswp(p, p + td->o.verify_offset, header_size);
+ hdr = p;
+
+ /*
+ * Make rand_seed check pass when have verifysort or
+ * verify_backlog.
+ */
+ if (td->o.verifysort || (td->flags & TD_F_VER_BACKLOG))
+ io_u->rand_seed = hdr->rand_seed;
+
+ if (td->o.verify != VERIFY_PATTERN_NO_HDR) {
+ ret = verify_header(io_u, td, hdr, hdr_num, hdr_inc);
+ if (ret)
+ return ret;
+ }
+
+ if (td->o.verify != VERIFY_NONE)
+ verify_type = td->o.verify;
+ else
+ verify_type = hdr->verify_type;
+
+ switch (verify_type) {
+ case VERIFY_HDR_ONLY:
+ /* Header is always verified, check if pattern is left
+ * for verification. */
+ if (td->o.verify_pattern_bytes)
+ ret = verify_io_u_pattern(hdr, &vc);
+ break;
+ case VERIFY_MD5:
+ ret = verify_io_u_md5(hdr, &vc);
+ break;
+ case VERIFY_CRC64:
+ ret = verify_io_u_crc64(hdr, &vc);
+ break;
+ case VERIFY_CRC32C:
+ case VERIFY_CRC32C_INTEL:
+ ret = verify_io_u_crc32c(hdr, &vc);
+ break;
+ case VERIFY_CRC32:
+ ret = verify_io_u_crc32(hdr, &vc);
+ break;
+ case VERIFY_CRC16:
+ ret = verify_io_u_crc16(hdr, &vc);
+ break;
+ case VERIFY_CRC7:
+ ret = verify_io_u_crc7(hdr, &vc);
+ break;
+ case VERIFY_SHA256:
+ ret = verify_io_u_sha256(hdr, &vc);
+ break;
+ case VERIFY_SHA512:
+ ret = verify_io_u_sha512(hdr, &vc);
+ break;
+ case VERIFY_XXHASH:
+ ret = verify_io_u_xxhash(hdr, &vc);
+ break;
+ case VERIFY_SHA1:
+ ret = verify_io_u_sha1(hdr, &vc);
+ break;
+ case VERIFY_PATTERN:
+ case VERIFY_PATTERN_NO_HDR:
+ ret = verify_io_u_pattern(hdr, &vc);
+ break;
+ default:
+ log_err("Bad verify type %u\n", hdr->verify_type);
+ ret = EINVAL;
+ }
+
+ if (ret && verify_type != hdr->verify_type)
+ log_err("fio: verify type mismatch (%u media, %u given)\n",
+ hdr->verify_type, verify_type);
+ }
+
+done:
+ if (ret && td->o.verify_fatal)
+ fio_mark_td_terminate(td);
+
+ return ret;
+}
+
+static void fill_xxhash(struct verify_header *hdr, void *p, unsigned int len)
+{
+ struct vhdr_xxhash *vh = hdr_priv(hdr);
+ void *state;
+
+ state = XXH32_init(1);
+ XXH32_update(state, p, len);
+ vh->hash = XXH32_digest(state);
+}
+
+static void fill_sha512(struct verify_header *hdr, void *p, unsigned int len)
+{
+ struct vhdr_sha512 *vh = hdr_priv(hdr);
+ struct fio_sha512_ctx sha512_ctx = {
+ .buf = vh->sha512,
+ };
+
+ fio_sha512_init(&sha512_ctx);
+ fio_sha512_update(&sha512_ctx, p, len);
+}
+
+static void fill_sha256(struct verify_header *hdr, void *p, unsigned int len)
+{
+ struct vhdr_sha256 *vh = hdr_priv(hdr);
+ struct fio_sha256_ctx sha256_ctx = {
+ .buf = vh->sha256,
+ };
+
+ fio_sha256_init(&sha256_ctx);
+ fio_sha256_update(&sha256_ctx, p, len);
+ fio_sha256_final(&sha256_ctx);
+}
+
+static void fill_sha1(struct verify_header *hdr, void *p, unsigned int len)
+{
+ struct vhdr_sha1 *vh = hdr_priv(hdr);
+ struct fio_sha1_ctx sha1_ctx = {
+ .H = vh->sha1,
+ };
+
+ fio_sha1_init(&sha1_ctx);
+ fio_sha1_update(&sha1_ctx, p, len);
+ fio_sha1_final(&sha1_ctx);
+}
+
+static void fill_crc7(struct verify_header *hdr, void *p, unsigned int len)
+{
+ struct vhdr_crc7 *vh = hdr_priv(hdr);
+
+ vh->crc7 = fio_crc7(p, len);
+}
+
+static void fill_crc16(struct verify_header *hdr, void *p, unsigned int len)
+{
+ struct vhdr_crc16 *vh = hdr_priv(hdr);
+
+ vh->crc16 = fio_crc16(p, len);
+}
+
+static void fill_crc32(struct verify_header *hdr, void *p, unsigned int len)
+{
+ struct vhdr_crc32 *vh = hdr_priv(hdr);
+
+ vh->crc32 = fio_crc32(p, len);
+}
+
+static void fill_crc32c(struct verify_header *hdr, void *p, unsigned int len)
+{
+ struct vhdr_crc32 *vh = hdr_priv(hdr);
+
+ vh->crc32 = fio_crc32c(p, len);
+}
+
+static void fill_crc64(struct verify_header *hdr, void *p, unsigned int len)
+{
+ struct vhdr_crc64 *vh = hdr_priv(hdr);
+
+ vh->crc64 = fio_crc64(p, len);
+}
+
+static void fill_md5(struct verify_header *hdr, void *p, unsigned int len)
+{
+ struct vhdr_md5 *vh = hdr_priv(hdr);
+ struct fio_md5_ctx md5_ctx = {
+ .hash = (uint32_t *) vh->md5_digest,
+ };
+
+ fio_md5_init(&md5_ctx);
+ fio_md5_update(&md5_ctx, p, len);
+ fio_md5_final(&md5_ctx);
+}
+
+static void __fill_hdr(struct thread_data *td, struct io_u *io_u,
+ struct verify_header *hdr, unsigned int header_num,
+ unsigned int header_len, uint64_t rand_seed)
+{
+ void *p = hdr;
+
+ hdr->magic = FIO_HDR_MAGIC;
+ hdr->verify_type = td->o.verify;
+ hdr->len = header_len;
+ hdr->rand_seed = rand_seed;
+ hdr->offset = io_u->offset + header_num * td->o.verify_interval;
+ hdr->time_sec = io_u->start_time.tv_sec;
+ hdr->time_usec = io_u->start_time.tv_usec;
+ hdr->thread = td->thread_number;
+ hdr->numberio = io_u->numberio;
+ hdr->crc32 = fio_crc32c(p, offsetof(struct verify_header, crc32));
+}
+
+
+static void fill_hdr(struct thread_data *td, struct io_u *io_u,
+ struct verify_header *hdr, unsigned int header_num,
+ unsigned int header_len, uint64_t rand_seed)
+{
+
+ if (td->o.verify != VERIFY_PATTERN_NO_HDR)
+ __fill_hdr(td, io_u, hdr, header_num, header_len, rand_seed);
+}
+
+static void populate_hdr(struct thread_data *td, struct io_u *io_u,
+ struct verify_header *hdr, unsigned int header_num,
+ unsigned int header_len)
+{
+ unsigned int data_len;
+ void *data, *p;
+
+ p = (void *) hdr;
+
+ fill_hdr(td, io_u, hdr, header_num, header_len, io_u->rand_seed);
+
+ data_len = header_len - hdr_size(td, hdr);
+
+ data = p + hdr_size(td, hdr);
+ switch (td->o.verify) {
+ case VERIFY_MD5:
+ dprint(FD_VERIFY, "fill md5 io_u %p, len %u\n",
+ io_u, hdr->len);
+ fill_md5(hdr, data, data_len);
+ break;
+ case VERIFY_CRC64:
+ dprint(FD_VERIFY, "fill crc64 io_u %p, len %u\n",
+ io_u, hdr->len);
+ fill_crc64(hdr, data, data_len);
+ break;
+ case VERIFY_CRC32C:
+ case VERIFY_CRC32C_INTEL:
+ dprint(FD_VERIFY, "fill crc32c io_u %p, len %u\n",
+ io_u, hdr->len);
+ fill_crc32c(hdr, data, data_len);
+ break;
+ case VERIFY_CRC32:
+ dprint(FD_VERIFY, "fill crc32 io_u %p, len %u\n",
+ io_u, hdr->len);
+ fill_crc32(hdr, data, data_len);
+ break;
+ case VERIFY_CRC16:
+ dprint(FD_VERIFY, "fill crc16 io_u %p, len %u\n",
+ io_u, hdr->len);
+ fill_crc16(hdr, data, data_len);
+ break;
+ case VERIFY_CRC7:
+ dprint(FD_VERIFY, "fill crc7 io_u %p, len %u\n",
+ io_u, hdr->len);
+ fill_crc7(hdr, data, data_len);
+ break;
+ case VERIFY_SHA256:
+ dprint(FD_VERIFY, "fill sha256 io_u %p, len %u\n",
+ io_u, hdr->len);
+ fill_sha256(hdr, data, data_len);
+ break;
+ case VERIFY_SHA512:
+ dprint(FD_VERIFY, "fill sha512 io_u %p, len %u\n",
+ io_u, hdr->len);
+ fill_sha512(hdr, data, data_len);
+ break;
+ case VERIFY_XXHASH:
+ dprint(FD_VERIFY, "fill xxhash io_u %p, len %u\n",
+ io_u, hdr->len);
+ fill_xxhash(hdr, data, data_len);
+ break;
+ case VERIFY_SHA1:
+ dprint(FD_VERIFY, "fill sha1 io_u %p, len %u\n",
+ io_u, hdr->len);
+ fill_sha1(hdr, data, data_len);
+ break;
+ case VERIFY_HDR_ONLY:
+ case VERIFY_PATTERN:
+ case VERIFY_PATTERN_NO_HDR:
+ /* nothing to do here */
+ break;
+ default:
+ log_err("fio: bad verify type: %d\n", td->o.verify);
+ assert(0);
+ }
+
+ if (td->o.verify_offset && hdr_size(td, hdr))
+ memswp(p, p + td->o.verify_offset, hdr_size(td, hdr));
+}
+
+/*
+ * fill body of io_u->buf with random data and add a header with the
+ * checksum of choice
+ */
+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);
+}
+
+int get_next_verify(struct thread_data *td, struct io_u *io_u)
+{
+ struct io_piece *ipo = NULL;
+
+ /*
+ * this io_u is from a requeue, we already filled the offsets
+ */
+ if (io_u->file)
+ return 0;
+
+ if (!RB_EMPTY_ROOT(&td->io_hist_tree)) {
+ struct rb_node *n = rb_first(&td->io_hist_tree);
+
+ ipo = rb_entry(n, struct io_piece, rb_node);
+
+ /*
+ * Ensure that the associated IO has completed
+ */
+ read_barrier();
+ if (ipo->flags & IP_F_IN_FLIGHT)
+ goto nothing;
+
+ rb_erase(n, &td->io_hist_tree);
+ assert(ipo->flags & IP_F_ONRB);
+ ipo->flags &= ~IP_F_ONRB;
+ } else if (!flist_empty(&td->io_hist_list)) {
+ ipo = flist_first_entry(&td->io_hist_list, struct io_piece, list);
+
+ /*
+ * Ensure that the associated IO has completed
+ */
+ read_barrier();
+ if (ipo->flags & IP_F_IN_FLIGHT)
+ goto nothing;
+
+ flist_del(&ipo->list);
+ assert(ipo->flags & IP_F_ONLIST);
+ ipo->flags &= ~IP_F_ONLIST;
+ }
+
+ if (ipo) {
+ td->io_hist_len--;
+
+ io_u->offset = ipo->offset;
+ io_u->buflen = ipo->len;
+ io_u->numberio = ipo->numberio;
+ io_u->file = ipo->file;
+ io_u_set(td, io_u, IO_U_F_VER_LIST);
+
+ if (ipo->flags & IP_F_TRIMMED)
+ io_u_set(td, io_u, IO_U_F_TRIMMED);
+
+ if (!fio_file_open(io_u->file)) {
+ int r = td_io_open_file(td, io_u->file);
+
+ if (r) {
+ dprint(FD_VERIFY, "failed file %s open\n",
+ io_u->file->file_name);
+ return 1;
+ }
+ }