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