verify.c revision 8c432325c3df2075a77b27eab8a87704cf7b48ee
1/* 2 * IO verification helpers 3 */ 4#include <unistd.h> 5#include <fcntl.h> 6#include <string.h> 7#include <assert.h> 8 9#include "fio.h" 10 11static void fill_random_bytes(struct thread_data *td, 12 unsigned char *p, unsigned int len) 13{ 14 unsigned int todo; 15 int r; 16 17 while (len) { 18 r = os_random_long(&td->verify_state); 19 20 /* 21 * lrand48_r seems to be broken and only fill the bottom 22 * 32-bits, even on 64-bit archs with 64-bit longs 23 */ 24 todo = sizeof(r); 25 if (todo > len) 26 todo = len; 27 28 memcpy(p, &r, todo); 29 30 len -= todo; 31 p += todo; 32 } 33} 34 35static void hexdump(void *buffer, int len) 36{ 37 unsigned char *p = buffer; 38 int i; 39 40 for (i = 0; i < len; i++) 41 log_info("%02x", p[i]); 42 log_info("\n"); 43} 44 45static int verify_io_u_crc7(struct verify_header *hdr, struct io_u *io_u) 46{ 47 unsigned char *p = io_u->buf; 48 unsigned char c; 49 50 p += sizeof(*hdr); 51 c = crc7(p, hdr->len - sizeof(*hdr)); 52 53 if (c != hdr->crc7) { 54 log_err("crc7: verify failed at %llu/%lu\n", io_u->offset, io_u->buflen); 55 log_err("crc7: wanted %x, got %x\n", hdr->crc7, c); 56 return 1; 57 } 58 59 return 0; 60} 61 62static int verify_io_u_crc16(struct verify_header *hdr, struct io_u *io_u) 63{ 64 unsigned char *p = io_u->buf; 65 unsigned short c; 66 67 p += sizeof(*hdr); 68 c = crc16(p, hdr->len - sizeof(*hdr)); 69 70 if (c != hdr->crc16) { 71 log_err("crc16: verify failed at %llu/%lu\n", io_u->offset, io_u->buflen); 72 log_err("crc16: wanted %x, got %x\n", hdr->crc16, c); 73 return 1; 74 } 75 76 return 0; 77} 78 79static int verify_io_u_crc32(struct verify_header *hdr, struct io_u *io_u) 80{ 81 unsigned char *p = io_u->buf; 82 unsigned long c; 83 84 p += sizeof(*hdr); 85 c = crc32(p, hdr->len - sizeof(*hdr)); 86 87 if (c != hdr->crc32) { 88 log_err("crc32: verify failed at %llu/%lu\n", io_u->offset, io_u->buflen); 89 log_err("crc32: wanted %lx, got %lx\n", hdr->crc32, c); 90 return 1; 91 } 92 93 return 0; 94} 95 96static int verify_io_u_md5(struct verify_header *hdr, struct io_u *io_u) 97{ 98 unsigned char *p = io_u->buf + sizeof(*hdr); 99 uint32_t hash[MD5_HASH_WORDS]; 100 struct md5_ctx md5_ctx = { 101 .hash = hash, 102 }; 103 104 md5_update(&md5_ctx, p, hdr->len - sizeof(*hdr)); 105 106 if (memcmp(hdr->md5_digest, md5_ctx.hash, sizeof(hash))) { 107 log_err("md5: verify failed at %llu/%lu\n", io_u->offset, io_u->buflen); 108 hexdump(hdr->md5_digest, sizeof(hdr->md5_digest)); 109 hexdump(md5_ctx.hash, sizeof(hash)); 110 return 1; 111 } 112 113 return 0; 114} 115 116int verify_io_u(struct thread_data *td, struct io_u *io_u) 117{ 118 struct verify_header *hdr = (struct verify_header *) io_u->buf; 119 int ret; 120 121 if (td->o.verify == VERIFY_NULL || io_u->ddir != DDIR_READ) 122 return 0; 123 124 if (hdr->fio_magic != FIO_HDR_MAGIC) { 125 log_err("Bad verify header %x\n", hdr->fio_magic); 126 return EIO; 127 } 128 129 switch (hdr->verify_type) { 130 case VERIFY_MD5: 131 ret = verify_io_u_md5(hdr, io_u); 132 break; 133 case VERIFY_CRC32: 134 ret = verify_io_u_crc32(hdr, io_u); 135 break; 136 case VERIFY_CRC16: 137 ret = verify_io_u_crc16(hdr, io_u); 138 break; 139 case VERIFY_CRC7: 140 ret = verify_io_u_crc7(hdr, io_u); 141 break; 142 default: 143 log_err("Bad verify type %u\n", hdr->verify_type); 144 ret = 1; 145 } 146 147 if (ret) 148 return EIO; 149 150 return 0; 151} 152 153static void fill_crc7(struct verify_header *hdr, void *p, unsigned int len) 154{ 155 hdr->crc7 = crc7(p, len); 156} 157 158static void fill_crc16(struct verify_header *hdr, void *p, unsigned int len) 159{ 160 hdr->crc16 = crc16(p, len); 161} 162 163static void fill_crc32(struct verify_header *hdr, void *p, unsigned int len) 164{ 165 hdr->crc32 = crc32(p, len); 166} 167 168static void fill_md5(struct verify_header *hdr, void *p, unsigned int len) 169{ 170 struct md5_ctx md5_ctx = { 171 .hash = (uint32_t *) hdr->md5_digest, 172 }; 173 174 md5_update(&md5_ctx, p, len); 175} 176 177/* 178 * fill body of io_u->buf with random data and add a header with the 179 * crc32 or md5 sum of that data. 180 */ 181void populate_verify_io_u(struct thread_data *td, struct io_u *io_u) 182{ 183 const unsigned int len = io_u->buflen - sizeof(struct verify_header); 184 struct verify_header *hdr; 185 unsigned char *p; 186 187 if (td->o.verify == VERIFY_NULL) 188 return; 189 190 hdr = (struct verify_header *) io_u->buf; 191 hdr->fio_magic = FIO_HDR_MAGIC; 192 hdr->len = io_u->buflen; 193 hdr->verify_type = td->o.verify; 194 195 p = io_u->buf + sizeof(*hdr); 196 fill_random_bytes(td, p, len); 197 198 switch (td->o.verify) { 199 case VERIFY_MD5: 200 fill_md5(hdr, p, len); 201 break; 202 case VERIFY_CRC32: 203 fill_crc32(hdr, p, len); 204 break; 205 case VERIFY_CRC16: 206 fill_crc16(hdr, p, len); 207 break; 208 case VERIFY_CRC7: 209 fill_crc7(hdr, p, len); 210 break; 211 default: 212 log_err("fio: bad verify type: %d\n", td->o.verify); 213 assert(0); 214 } 215} 216 217int get_next_verify(struct thread_data *td, struct io_u *io_u) 218{ 219 struct io_piece *ipo = NULL; 220 221 /* 222 * this io_u is from a requeue, we already filled the offsets 223 */ 224 if (io_u->file) 225 return 0; 226 227 if (!RB_EMPTY_ROOT(&td->io_hist_tree)) { 228 struct rb_node *n = rb_first(&td->io_hist_tree); 229 230 ipo = rb_entry(n, struct io_piece, rb_node); 231 rb_erase(n, &td->io_hist_tree); 232 } else if (!list_empty(&td->io_hist_list)) { 233 ipo = list_entry(td->io_hist_list.next, struct io_piece, list); 234 list_del(&ipo->list); 235 } 236 237 if (ipo) { 238 io_u->offset = ipo->offset; 239 io_u->buflen = ipo->len; 240 io_u->file = ipo->file; 241 242 if ((io_u->file->flags & FIO_FILE_OPEN) == 0) { 243 int r = td_io_open_file(td, io_u->file); 244 245 if (r) 246 return 1; 247 } 248 249 get_file(ipo->file); 250 assert(io_u->file->flags & FIO_FILE_OPEN); 251 io_u->ddir = DDIR_READ; 252 io_u->xfer_buf = io_u->buf; 253 io_u->xfer_buflen = io_u->buflen; 254 free(ipo); 255 return 0; 256 } 257 258 return 1; 259} 260