ia64/xen-unstable

view tools/blktap2/drivers/tapdisk-filter.c @ 19817:b7f73a7f3078

blktap2: portability fixes for NetBSD

- Use standard off_t and lseek() instead of non-portable off64_t and
lseek64()
- Use uuid API as documented in DCE 1.1 RPC specification
- Add NetBSD implementation for blk_getimagesize() and
blk_getsectorsize()
- Use blk_getimagesize() and blk_getsectorsize()
- Fix uuid header check

Signed-off-by: Christoph Egger <Christoph.Egger@amd.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Jun 23 17:24:14 2009 +0100 (2009-06-23)
parents 1c627434605e
children
line source
1 /*
2 * Copyright (c) 2008, XenSource Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of XenSource Inc. nor the names of its contributors
13 * may be used to endorse or promote products derived from this software
14 * without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
20 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <libaio.h>
32 #include <syslog.h>
33 #include <sys/time.h>
35 #include "tapdisk-log.h"
36 #include "tapdisk-filter.h"
38 #define RSEED 7
39 #define PRE_CHECK 0
40 #define POST_CHECK 1
42 #define WRITE_INTEGRITY "buffer integrity failure after write"
43 #define READ_INTEGRITY "disk integrity failure after read"
45 #define DBG(f, a...) tlog_write(TLOG_WARN, f, ##a)
47 /*
48 * simulate IO errors by knocking request size to zero before
49 * submitting and restoring original size before returning
50 */
51 static inline void
52 inject_fault(struct tfilter *filter, struct iocb *io)
53 {
54 struct fiocb *fio;
56 if (!filter->ffree)
57 return;
59 fio = filter->flist[--filter->ffree];
61 fio->bytes = io->u.c.nbytes;
62 fio->data = io->data;
63 io->u.c.nbytes = 0;
64 io->data = fio;
65 }
67 static inline int
68 fault_injected(struct tfilter *filter, struct iocb *io)
69 {
70 unsigned long iop = (unsigned long)io->data;
71 unsigned long start = (unsigned long)filter->fiocbs;
72 unsigned long end = start + (filter->iocbs * sizeof(struct fiocb));
74 return (iop >= start && iop < end);
75 }
77 static inline void
78 recover_fault(struct tfilter *filter, struct iocb *io)
79 {
80 struct fiocb *fio = (struct fiocb *)io->data;
82 io->u.c.nbytes = fio->bytes;
83 io->data = fio->data;
85 memset(fio, 0, sizeof(struct fiocb));
86 filter->flist[filter->ffree++] = fio;
87 }
89 static inline uint64_t
90 chksum(char *buf)
91 {
92 int i, num = 512 >> 3;
93 uint64_t *p = (uint64_t *)buf;
94 uint64_t sum = 0;
96 for (i = 0; i < num; i++)
97 sum += p[i];
99 return sum;
100 }
102 static inline void
103 check_hash(struct tfilter *filter, uint64_t sec, char *buf, char *type)
104 {
105 uint64_t sum;
106 struct dhash *hash;
108 hash = filter->dhash + sec;
109 if (!hash->time.tv_sec)
110 return;
112 sum = chksum(buf);
113 if (hash->hash != chksum(buf)) {
114 struct timeval now;
115 gettimeofday(&now, NULL);
116 DBG("%s: hash table: 0x%020" PRIx64 " at %012lu.%06llu, "
117 "from disk: 0x%020" PRIx64 " at %012lu.%06llu\n",
118 type, hash->hash, hash->time.tv_sec,
119 (unsigned long long)hash->time.tv_usec, sum,
120 now.tv_sec, (unsigned long long)now.tv_usec);
121 }
122 }
124 static inline void
125 insert_hash(struct tfilter *filter, uint64_t sec, char *buf)
126 {
127 struct dhash *hash;
129 hash = filter->dhash + sec;
130 hash->hash = chksum(buf);
131 gettimeofday(&hash->time, NULL);
132 }
134 static void
135 check_sector(struct tfilter *filter, int type, int rw, uint64_t sec, char *buf)
136 {
137 struct dhash *hash;
139 if (sec >= filter->secs)
140 return;
142 hash = filter->dhash + sec;
144 if (rw) {
145 if (type == PRE_CHECK)
146 insert_hash(filter, sec, buf);
147 else
148 check_hash(filter, sec, buf, WRITE_INTEGRITY);
149 } else if (type == POST_CHECK) {
150 check_hash(filter, sec, buf, READ_INTEGRITY);
151 insert_hash(filter, sec, buf);
152 }
153 }
155 static void
156 check_data(struct tfilter *filter, int type, struct iocb *io)
157 {
158 int rw;
159 uint64_t i, sec;
161 rw = (io->aio_lio_opcode == IO_CMD_PWRITE);
163 for (i = 0; i < io->u.c.nbytes; i += 512) {
164 char *buf = io->u.c.buf + i;
165 uint64_t sec = (io->u.c.offset + i) >> 9;
166 check_sector(filter, type, rw, sec, buf);
167 }
168 }
170 struct tfilter *
171 tapdisk_init_tfilter(int mode, int iocbs, uint64_t secs)
172 {
173 int i;
174 struct tfilter *filter = NULL;
176 if (!mode)
177 return NULL;
179 filter = calloc(1, sizeof(struct tfilter));
180 if (!filter)
181 goto fail;
183 filter->mode = mode;
184 filter->secs = secs;
185 filter->iocbs = iocbs;
187 if (filter->mode & TD_INJECT_FAULTS) {
188 filter->fiocbs = calloc(iocbs, sizeof(struct fiocb));
189 filter->flist = calloc(iocbs, sizeof(struct fiocb *));
190 if (!filter->fiocbs || !filter->flist)
191 filter->mode &= ~TD_INJECT_FAULTS;
192 else {
193 srand(RSEED);
194 filter->ffree = iocbs;
195 for (i = 0; i < iocbs; i++)
196 filter->flist[i] = filter->fiocbs + i;
197 }
198 }
200 if (filter->mode & TD_CHECK_INTEGRITY) {
201 filter->dhash = calloc(secs, sizeof(struct dhash));
202 if (!filter->dhash)
203 filter->mode &= ~TD_CHECK_INTEGRITY;
204 }
206 syslog(LOG_WARNING, "WARNING: "
207 "FILTERING IN MODE 0x%04x\n", filter->mode);
209 return filter;
211 fail:
212 tapdisk_free_tfilter(filter);
213 return NULL;
214 }
216 void
217 tapdisk_free_tfilter(struct tfilter *filter)
218 {
219 if (!filter)
220 return;
222 free(filter->dhash);
223 free(filter->flist);
224 free(filter->fiocbs);
225 free(filter);
226 }
228 void
229 tapdisk_filter_iocbs(struct tfilter *filter, struct iocb **iocbs, int num)
230 {
231 int i;
233 if (!filter)
234 return;
236 for (i = 0; i < num; i++) {
237 struct iocb *io = iocbs[i];
239 if (filter->mode & TD_INJECT_FAULTS) {
240 if ((random() % 100) <= TD_FAULT_RATE) {
241 inject_fault(filter, io);
242 continue;
243 }
244 }
246 if (filter->mode & TD_CHECK_INTEGRITY)
247 check_data(filter, PRE_CHECK, io);
248 }
249 }
251 void
252 tapdisk_filter_events(struct tfilter *filter, struct io_event *events, int num)
253 {
254 int i;
256 if (!filter)
257 return;
259 for (i = 0; i < num; i++) {
260 struct iocb *io = events[i].obj;
262 if (filter->mode & TD_INJECT_FAULTS) {
263 if (fault_injected(filter, io)) {
264 recover_fault(filter, io);
265 continue;
266 }
267 }
269 if (filter->mode & TD_CHECK_INTEGRITY)
270 check_data(filter, POST_CHECK, io);
271 }
272 }