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