Remove .maxval from verify_pattern
[fio.git] / verify.c
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
11 static void fill_random_bytes(struct thread_data *td, void *p, unsigned int len)
12 {
13         unsigned int todo;
14         int r;
15
16         while (len) {
17                 r = os_random_long(&td->verify_state);
18
19                 /*
20                  * lrand48_r seems to be broken and only fill the bottom
21                  * 32-bits, even on 64-bit archs with 64-bit longs
22                  */
23                 todo = sizeof(r);
24                 if (todo > len)
25                         todo = len;
26
27                 memcpy(p, &r, todo);
28
29                 len -= todo;
30                 p += todo;
31         }
32 }
33
34 static void fill_pattern(struct thread_data *td, void *p, unsigned int len)
35 {
36         switch (td->o.verify_pattern_bytes) {
37         case 0:
38                 fill_random_bytes(td, p, len);
39                 break;
40         case 1:
41                 memset(p, td->o.verify_pattern, len);
42                 break;
43         case 2:
44         case 3:
45         case 4: {
46                 unsigned int pattern = td->o.verify_pattern;
47                 unsigned int i = 0;
48                 unsigned char c1, c2, c3, c4;
49                 unsigned char *b = p;
50
51                 c1 = pattern & 0xff;
52                 pattern >>= 8;
53                 c2 = pattern & 0xff;
54                 pattern >>= 8;
55                 c3 = pattern & 0xff;
56                 pattern >>= 8;
57                 c4 = pattern & 0xff;
58
59                 while (i < len) {
60                         b[i++] = c1;
61                         if (i == len)
62                                 break;
63                         b[i++] = c2;
64                         if (td->o.verify_pattern_bytes == 2 || i == len)
65                                 continue;
66                         b[i++] = c3;
67                         if (td->o.verify_pattern_bytes == 3 || i == len)
68                                 continue;
69                         b[i++] = c4;
70                 }
71                 break;
72                 }
73         }
74 }
75
76 static void memswp(void* buf1, void* buf2, unsigned int len)
77 {
78         struct verify_header swap;
79
80         memcpy(&swap, buf1, len);
81         memcpy(buf1, buf2, len);
82         memcpy(buf2, &swap, len);
83 }
84
85 static void hexdump(void *buffer, int len)
86 {
87         unsigned char *p = buffer;
88         int i;
89
90         for (i = 0; i < len; i++)
91                 log_info("%02x", p[i]);
92         log_info("\n");
93 }
94
95 /*
96  * Return data area 'header_num'
97  */
98 static inline void *io_u_verify_off(struct verify_header *hdr,
99                                     struct io_u *io_u,
100                                     unsigned char header_num)
101 {
102         return io_u->buf + sizeof(*hdr) + header_num * hdr->len;
103 }
104
105 static int verify_io_u_crc7(struct verify_header *hdr, struct io_u *io_u,
106                             unsigned char header_num)
107 {
108         void *p = io_u_verify_off(hdr, io_u, header_num);
109         unsigned char c;
110
111         c = crc7(p, hdr->len - sizeof(*hdr));
112
113         if (c != hdr->crc7) {
114                 log_err("crc7: verify failed at %llu/%u\n",
115                                 io_u->offset + header_num * hdr->len,
116                                 hdr->len);
117                 log_err("crc7: wanted %x, got %x\n", hdr->crc7, c);
118                 return 1;
119         }
120
121         return 0;
122 }
123
124 static int verify_io_u_crc16(struct verify_header *hdr, struct io_u *io_u,
125                              unsigned int header_num)
126 {
127         void *p = io_u_verify_off(hdr, io_u, header_num);
128         unsigned short c;
129
130         c = crc16(p, hdr->len - sizeof(*hdr));
131
132         if (c != hdr->crc16) {
133                 log_err("crc16: verify failed at %llu/%u\n",
134                                 io_u->offset + header_num * hdr->len,
135                                 hdr->len);
136                 log_err("crc16: wanted %x, got %x\n", hdr->crc16, c);
137                 return 1;
138         }
139
140         return 0;
141 }
142
143 static int verify_io_u_crc64(struct verify_header *hdr, struct io_u *io_u,
144                              unsigned int header_num)
145 {
146         void *p = io_u_verify_off(hdr, io_u, header_num);
147         unsigned long long c;
148
149         c = crc64(p, hdr->len - sizeof(*hdr));
150
151         if (c != hdr->crc64) {
152                 log_err("crc64: verify failed at %llu/%u\n",
153                                 io_u->offset + header_num * hdr->len,
154                                 hdr->len);
155                 log_err("crc64: wanted %llx, got %llx\n", hdr->crc64, c);
156                 return 1;
157         }
158
159         return 0;
160 }
161
162 static int verify_io_u_crc32(struct verify_header *hdr, struct io_u *io_u,
163                              unsigned int header_num)
164 {
165         void *p = io_u_verify_off(hdr, io_u, header_num);
166         unsigned long c;
167
168         c = crc32(p, hdr->len - sizeof(*hdr));
169
170         if (c != hdr->crc32) {
171                 log_err("crc32: verify failed at %llu/%u\n",
172                                 io_u->offset + header_num * hdr->len,
173                                 hdr->len);
174                 log_err("crc32: wanted %lx, got %lx\n", hdr->crc32, c);
175                 return 1;
176         }
177
178         return 0;
179 }
180
181 static int verify_io_u_md5(struct verify_header *hdr, struct io_u *io_u,
182                            unsigned int header_num)
183 {
184         void *p = io_u_verify_off(hdr, io_u, header_num);
185         uint32_t hash[MD5_HASH_WORDS];
186         struct md5_ctx md5_ctx = {
187                 .hash = hash,
188         };
189
190         memset(md5_ctx.hash, 0, sizeof(hdr->md5_digest));
191         md5_update(&md5_ctx, p, hdr->len - sizeof(*hdr));
192
193         if (memcmp(hdr->md5_digest, md5_ctx.hash, sizeof(hash))) {
194                 log_err("md5: verify failed at %llu/%u\n",
195                               io_u->offset + header_num * hdr->len,
196                               hdr->len);
197                 hexdump(hdr->md5_digest, sizeof(hdr->md5_digest));
198                 hexdump(md5_ctx.hash, sizeof(hash));
199                 return 1;
200         }
201
202         return 0;
203 }
204
205 int verify_io_u(struct thread_data *td, struct io_u *io_u)
206 {
207         struct verify_header *hdr;
208         unsigned int hdr_inc, hdr_num = 0;
209         void *p;
210         int ret;
211
212         if (td->o.verify == VERIFY_NULL || io_u->ddir != DDIR_READ)
213                 return 0;
214
215         hdr_inc = io_u->buflen;
216         if (td->o.verify_interval)
217                 hdr_inc = td->o.verify_interval;
218
219         for (p = io_u->buf; p < io_u->buf + io_u->buflen; p += hdr_inc) {
220                 if (td->o.verify_offset)
221                         memswp(p, p + td->o.verify_offset, sizeof(*hdr));
222
223                 hdr = p;
224
225                 if (hdr->fio_magic != FIO_HDR_MAGIC) {
226                         log_err("Bad verify header %x\n", hdr->fio_magic);
227                         return EIO;
228                 }
229
230                 switch (hdr->verify_type) {
231                 case VERIFY_MD5:
232                         ret = verify_io_u_md5(hdr, io_u, hdr_num);
233                         break;
234                 case VERIFY_CRC64:
235                         ret = verify_io_u_crc64(hdr, io_u, hdr_num);
236                         break;
237                 case VERIFY_CRC32:
238                         ret = verify_io_u_crc32(hdr, io_u, hdr_num);
239                         break;
240                 case VERIFY_CRC16:
241                         ret = verify_io_u_crc16(hdr, io_u, hdr_num);
242                         break;
243                 case VERIFY_CRC7:
244                         ret = verify_io_u_crc7(hdr, io_u, hdr_num);
245                         break;
246                 default:
247                         log_err("Bad verify type %u\n", hdr->verify_type);
248                         ret = 1;
249                 }
250                 hdr_num++;
251         }
252
253         return 0;
254 }
255
256 static void fill_crc7(struct verify_header *hdr, void *p, unsigned int len)
257 {
258         hdr->crc7 = crc7(p, len);
259 }
260
261 static void fill_crc16(struct verify_header *hdr, void *p, unsigned int len)
262 {
263         hdr->crc16 = crc16(p, len);
264 }
265
266 static void fill_crc32(struct verify_header *hdr, void *p, unsigned int len)
267 {
268         hdr->crc32 = crc32(p, len);
269 }
270
271 static void fill_crc64(struct verify_header *hdr, void *p, unsigned int len)
272 {
273         hdr->crc64 = crc64(p, len);
274 }
275
276 static void fill_md5(struct verify_header *hdr, void *p, unsigned int len)
277 {
278         struct md5_ctx md5_ctx = {
279                 .hash = (uint32_t *) hdr->md5_digest,
280         };
281
282         memset(md5_ctx.hash, 0, sizeof(hdr->md5_digest));
283         md5_update(&md5_ctx, p, len);
284 }
285
286 /*
287  * fill body of io_u->buf with random data and add a header with the
288  * crc32 or md5 sum of that data.
289  */
290 void populate_verify_io_u(struct thread_data *td, struct io_u *io_u)
291 {
292         struct verify_header *hdr;
293         void *p = io_u->buf, *data;
294         unsigned int hdr_inc, data_len;
295
296         if (td->o.verify == VERIFY_NULL)
297                 return;
298
299         fill_pattern(td, p, io_u->buflen);
300
301         hdr_inc = io_u->buflen;
302         if (td->o.verify_interval)
303                 hdr_inc = td->o.verify_interval;
304         data_len = hdr_inc - sizeof(*hdr);
305
306         for (;p < io_u->buf + io_u->buflen; p += hdr_inc) {
307                 hdr = p;
308
309                 hdr->fio_magic = FIO_HDR_MAGIC;
310                 hdr->verify_type = td->o.verify;
311                 hdr->len = hdr_inc;
312
313                 data = p + sizeof(*hdr);
314                 switch (td->o.verify) {
315                 case VERIFY_MD5:
316                         fill_md5(hdr, data, data_len);
317                         break;
318                 case VERIFY_CRC64:
319                         fill_crc64(hdr, data, data_len);
320                         break;
321                 case VERIFY_CRC32:
322                         fill_crc32(hdr, data, data_len);
323                         break;
324                 case VERIFY_CRC16:
325                         fill_crc16(hdr, data, data_len);
326                         break;
327                 case VERIFY_CRC7:
328                         fill_crc7(hdr, data, data_len);
329                         break;
330                 default:
331                         log_err("fio: bad verify type: %d\n", td->o.verify);
332                         assert(0);
333                 }
334                 if (td->o.verify_offset)
335                         memswp(p, p + td->o.verify_offset, sizeof(*hdr));
336         }
337 }
338
339 int get_next_verify(struct thread_data *td, struct io_u *io_u)
340 {
341         struct io_piece *ipo = NULL;
342
343         /*
344          * this io_u is from a requeue, we already filled the offsets
345          */
346         if (io_u->file)
347                 return 0;
348
349         if (!RB_EMPTY_ROOT(&td->io_hist_tree)) {
350                 struct rb_node *n = rb_first(&td->io_hist_tree);
351
352                 ipo = rb_entry(n, struct io_piece, rb_node);
353                 rb_erase(n, &td->io_hist_tree);
354         } else if (!list_empty(&td->io_hist_list)) {
355                 ipo = list_entry(td->io_hist_list.next, struct io_piece, list);
356                 list_del(&ipo->list);
357         }
358
359         if (ipo) {
360                 io_u->offset = ipo->offset;
361                 io_u->buflen = ipo->len;
362                 io_u->file = ipo->file;
363
364                 if ((io_u->file->flags & FIO_FILE_OPEN) == 0) {
365                         int r = td_io_open_file(td, io_u->file);
366
367                         if (r)
368                                 return 1;
369                 }
370
371                 get_file(ipo->file);
372                 assert(io_u->file->flags & FIO_FILE_OPEN);
373                 io_u->ddir = DDIR_READ;
374                 io_u->xfer_buf = io_u->buf;
375                 io_u->xfer_buflen = io_u->buflen;
376                 free(ipo);
377                 return 0;
378         }
379
380         return 1;
381 }