2
* Copyright (c) 2008, XenSource Inc.
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.
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.
35
#include "tapdisk-log.h"
36
#include "tapdisk-filter.h"
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)
48
* simulate IO errors by knocking request size to zero before
49
* submitting and restoring original size before returning
52
inject_fault(struct tfilter *filter, struct iocb *io)
59
fio = filter->flist[--filter->ffree];
61
fio->bytes = io->u.c.nbytes;
68
fault_injected(struct tfilter *filter, struct iocb *io)
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);
78
recover_fault(struct tfilter *filter, struct iocb *io)
80
struct fiocb *fio = (struct fiocb *)io->data;
82
io->u.c.nbytes = fio->bytes;
85
memset(fio, 0, sizeof(struct fiocb));
86
filter->flist[filter->ffree++] = fio;
89
static inline uint64_t
92
int i, num = 512 >> 3;
93
uint64_t *p = (uint64_t *)buf;
96
for (i = 0; i < num; i++)
103
check_hash(struct tfilter *filter, uint64_t sec, char *buf, char *type)
108
hash = filter->dhash + sec;
109
if (!hash->time.tv_sec)
113
if (hash->hash != chksum(buf)) {
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);
125
insert_hash(struct tfilter *filter, uint64_t sec, char *buf)
129
hash = filter->dhash + sec;
130
hash->hash = chksum(buf);
131
gettimeofday(&hash->time, NULL);
135
check_sector(struct tfilter *filter, int type, int rw, uint64_t sec, char *buf)
139
if (sec >= filter->secs)
142
hash = filter->dhash + sec;
145
if (type == PRE_CHECK)
146
insert_hash(filter, sec, buf);
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);
156
check_data(struct tfilter *filter, int type, struct iocb *io)
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);
171
tapdisk_init_tfilter(int mode, int iocbs, uint64_t secs)
174
struct tfilter *filter = NULL;
179
filter = calloc(1, sizeof(struct tfilter));
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;
194
filter->ffree = iocbs;
195
for (i = 0; i < iocbs; i++)
196
filter->flist[i] = filter->fiocbs + i;
200
if (filter->mode & TD_CHECK_INTEGRITY) {
201
filter->dhash = calloc(secs, sizeof(struct dhash));
203
filter->mode &= ~TD_CHECK_INTEGRITY;
206
syslog(LOG_WARNING, "WARNING: "
207
"FILTERING IN MODE 0x%04x\n", filter->mode);
212
tapdisk_free_tfilter(filter);
217
tapdisk_free_tfilter(struct tfilter *filter)
224
free(filter->fiocbs);
229
tapdisk_filter_iocbs(struct tfilter *filter, struct iocb **iocbs, int num)
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);
246
if (filter->mode & TD_CHECK_INTEGRITY)
247
check_data(filter, PRE_CHECK, io);
252
tapdisk_filter_events(struct tfilter *filter, struct io_event *events, int num)
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);
269
if (filter->mode & TD_CHECK_INTEGRITY)
270
check_data(filter, POST_CHECK, io);