+ log_err("%02x", p[i]);
+ log_err("\n");
+}
+
+/*
+ * Prepare for seperation of verify_header and checksum header
+ */
+static inline unsigned int __hdr_size(int verify_type)
+{
+ unsigned int len = 0;
+
+ switch (verify_type) {
+ case VERIFY_NONE:
+ case VERIFY_NULL:
+ len = 0;
+ break;
+ case VERIFY_MD5:
+ len = sizeof(struct vhdr_md5);
+ break;
+ case VERIFY_CRC64:
+ len = sizeof(struct vhdr_crc64);
+ break;
+ case VERIFY_CRC32C:
+ case VERIFY_CRC32:
+ case VERIFY_CRC32C_INTEL:
+ len = sizeof(struct vhdr_crc32);
+ break;
+ case VERIFY_CRC16:
+ len = sizeof(struct vhdr_crc16);
+ break;
+ case VERIFY_CRC7:
+ len = sizeof(struct vhdr_crc7);
+ break;
+ case VERIFY_SHA256:
+ len = sizeof(struct vhdr_sha256);
+ break;
+ case VERIFY_SHA512:
+ len = sizeof(struct vhdr_sha512);
+ break;
+ case VERIFY_META:
+ len = sizeof(struct vhdr_meta);
+ break;
+ case VERIFY_SHA1:
+ len = sizeof(struct vhdr_sha1);
+ break;
+ case VERIFY_PATTERN:
+ len = 0;
+ break;
+ default:
+ log_err("fio: unknown verify header!\n");
+ assert(0);
+ }
+
+ return len + sizeof(struct verify_header);
+}
+
+static inline unsigned int hdr_size(struct verify_header *hdr)
+{
+ return __hdr_size(hdr->verify_type);
+}
+
+static void *hdr_priv(struct verify_header *hdr)
+{
+ void *priv = hdr;
+
+ return priv + sizeof(struct verify_header);
+}
+
+/*
+ * Verify container, pass info to verify handlers and allow them to
+ * pass info back in case of error
+ */
+struct vcont {
+ /*
+ * Input
+ */
+ struct io_u *io_u;
+ unsigned int hdr_num;
+ struct thread_data *td;
+
+ /*
+ * Output, only valid in case of error
+ */
+ const char *name;
+ void *good_crc;
+ void *bad_crc;
+ unsigned int crc_len;
+};
+
+static void dump_buf(char *buf, unsigned int len, unsigned long long offset,
+ const char *type, struct fio_file *f)
+{
+ char *ptr, fname[256];
+ int ret, fd;
+
+ ptr = strdup(f->file_name);
+ strcpy(fname, basename(ptr));
+
+ sprintf(fname + strlen(fname), ".%llu.%s", offset, type);
+
+ fd = open(fname, O_CREAT | O_TRUNC | O_WRONLY, 0644);
+ if (fd < 0) {
+ perror("open verify buf file");
+ return;
+ }
+
+ while (len) {
+ ret = write(fd, buf, len);
+ if (!ret)
+ break;
+ else if (ret < 0) {
+ perror("write verify buf file");
+ break;
+ }
+ len -= ret;
+ buf += ret;
+ }
+
+ close(fd);
+ log_err(" %s data dumped as %s\n", type, fname);
+ free(ptr);
+}
+
+/*
+ * Dump the contents of the read block and re-generate the correct data
+ * and dump that too.
+ */
+static void dump_verify_buffers(struct verify_header *hdr, struct vcont *vc)
+{
+ struct thread_data *td = vc->td;
+ struct io_u *io_u = vc->io_u;
+ unsigned long hdr_offset;
+ struct io_u dummy;
+ void *buf;
+
+ if (!td->o.verify_dump)
+ return;
+
+ /*
+ * Dump the contents we just read off disk
+ */
+ hdr_offset = vc->hdr_num * hdr->len;
+
+ dump_buf(io_u->buf + hdr_offset, hdr->len, io_u->offset + hdr_offset,
+ "received", vc->io_u->file);
+
+ /*
+ * Allocate a new buf and re-generate the original data
+ */
+ buf = malloc(io_u->buflen);
+ dummy = *io_u;
+ dummy.buf = buf;
+ dummy.rand_seed = hdr->rand_seed;
+ dummy.buf_filled_len = 0;
+
+ fill_pattern_headers(td, &dummy, hdr->rand_seed, 1);
+
+ dump_buf(buf + hdr_offset, hdr->len, io_u->offset + hdr_offset,
+ "expected", vc->io_u->file);
+ free(buf);
+}
+
+static void log_verify_failure(struct verify_header *hdr, struct vcont *vc)
+{
+ unsigned long long offset;
+
+ offset = vc->io_u->offset;
+ offset += vc->hdr_num * hdr->len;
+ log_err("%.8s: verify failed at file %s offset %llu, length %u\n",
+ vc->name, vc->io_u->file->file_name, offset, hdr->len);
+
+ if (vc->good_crc && vc->bad_crc) {
+ log_err(" Expected CRC: ");
+ hexdump(vc->good_crc, vc->crc_len);
+ log_err(" Received CRC: ");
+ hexdump(vc->bad_crc, vc->crc_len);
+ }
+
+ dump_verify_buffers(hdr, vc);