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