~ubuntu-branches/ubuntu/utopic/xen/utopic

« back to all changes in this revision

Viewing changes to tools/blktap2/drivers/tapdisk-filter.c

  • Committer: Bazaar Package Importer
  • Author(s): Bastian Blank
  • Date: 2010-05-06 15:47:38 UTC
  • mto: (1.3.1) (15.1.1 sid) (4.1.1 experimental)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20100506154738-agoz0rlafrh1fnq7
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
*/
 
28
 
 
29
#include <stdlib.h>
 
30
#include <unistd.h>
 
31
#include <libaio.h>
 
32
#include <syslog.h>
 
33
#include <sys/time.h>
 
34
 
 
35
#include "tapdisk-log.h"
 
36
#include "tapdisk-filter.h"
 
37
 
 
38
#define RSEED      7
 
39
#define PRE_CHECK  0
 
40
#define POST_CHECK 1
 
41
 
 
42
#define WRITE_INTEGRITY   "buffer integrity failure after write"
 
43
#define READ_INTEGRITY    "disk integrity failure after read"
 
44
 
 
45
#define DBG(f, a...) tlog_write(TLOG_WARN, f, ##a)
 
46
 
 
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;
 
55
 
 
56
        if (!filter->ffree)
 
57
                return;
 
58
 
 
59
        fio = filter->flist[--filter->ffree];
 
60
 
 
61
        fio->bytes     = io->u.c.nbytes;
 
62
        fio->data      = io->data;
 
63
        io->u.c.nbytes = 0;
 
64
        io->data       = fio;
 
65
}
 
66
 
 
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));
 
73
 
 
74
        return (iop >= start && iop < end);
 
75
}
 
76
 
 
77
static inline void
 
78
recover_fault(struct tfilter *filter, struct iocb *io)
 
79
{
 
80
        struct fiocb *fio = (struct fiocb *)io->data;
 
81
 
 
82
        io->u.c.nbytes = fio->bytes;
 
83
        io->data       = fio->data;
 
84
 
 
85
        memset(fio, 0, sizeof(struct fiocb));
 
86
        filter->flist[filter->ffree++] = fio;
 
87
}
 
88
 
 
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;
 
95
 
 
96
        for (i = 0; i < num; i++)
 
97
                sum += p[i];
 
98
 
 
99
        return sum;
 
100
}
 
101
 
 
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;
 
107
 
 
108
        hash = filter->dhash + sec;
 
109
        if (!hash->time.tv_sec)
 
110
                return;
 
111
 
 
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
}
 
123
 
 
124
static inline void
 
125
insert_hash(struct tfilter *filter, uint64_t sec, char *buf)
 
126
{
 
127
        struct dhash *hash;
 
128
 
 
129
        hash = filter->dhash + sec;
 
130
        hash->hash = chksum(buf);
 
131
        gettimeofday(&hash->time, NULL);
 
132
}
 
133
 
 
134
static void
 
135
check_sector(struct tfilter *filter, int type, int rw, uint64_t sec, char *buf)
 
136
{
 
137
        struct dhash *hash;
 
138
 
 
139
        if (sec >= filter->secs)
 
140
                return;
 
141
 
 
142
        hash = filter->dhash + sec;
 
143
 
 
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
}
 
154
 
 
155
static void
 
156
check_data(struct tfilter *filter, int type, struct iocb *io)
 
157
{
 
158
        int rw;
 
159
        uint64_t i, sec;
 
160
 
 
161
        rw = (io->aio_lio_opcode == IO_CMD_PWRITE);
 
162
 
 
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
}
 
169
 
 
170
struct tfilter *
 
171
tapdisk_init_tfilter(int mode, int iocbs, uint64_t secs)
 
172
{
 
173
        int i;
 
174
        struct tfilter *filter = NULL;
 
175
 
 
176
        if (!mode)
 
177
                return NULL;
 
178
 
 
179
        filter = calloc(1, sizeof(struct tfilter));
 
180
        if (!filter)
 
181
                goto fail;
 
182
 
 
183
        filter->mode  = mode;
 
184
        filter->secs  = secs;
 
185
        filter->iocbs = iocbs;
 
186
 
 
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
        }
 
199
 
 
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
        }
 
205
 
 
206
        syslog(LOG_WARNING, "WARNING: "
 
207
               "FILTERING IN MODE 0x%04x\n", filter->mode);
 
208
 
 
209
        return filter;
 
210
 
 
211
 fail:
 
212
        tapdisk_free_tfilter(filter);
 
213
        return NULL;
 
214
}
 
215
 
 
216
void
 
217
tapdisk_free_tfilter(struct tfilter *filter)
 
218
{
 
219
        if (!filter)
 
220
                return;
 
221
 
 
222
        free(filter->dhash);
 
223
        free(filter->flist);
 
224
        free(filter->fiocbs);
 
225
        free(filter);
 
226
}
 
227
 
 
228
void
 
229
tapdisk_filter_iocbs(struct tfilter *filter, struct iocb **iocbs, int num)
 
230
{
 
231
        int i;
 
232
 
 
233
        if (!filter)
 
234
                return;
 
235
 
 
236
        for (i = 0; i < num; i++) {
 
237
                struct iocb *io = iocbs[i];
 
238
 
 
239
                if (filter->mode & TD_INJECT_FAULTS) {
 
240
                        if ((random() % 100) <= TD_FAULT_RATE) {
 
241
                                inject_fault(filter, io);
 
242
                                continue;
 
243
                        }
 
244
                }
 
245
 
 
246
                if (filter->mode & TD_CHECK_INTEGRITY)
 
247
                        check_data(filter, PRE_CHECK, io);
 
248
        }
 
249
}
 
250
 
 
251
void
 
252
tapdisk_filter_events(struct tfilter *filter, struct io_event *events, int num)
 
253
{
 
254
        int i;
 
255
 
 
256
        if (!filter)
 
257
                return;
 
258
 
 
259
        for (i = 0; i < num; i++) {
 
260
                struct iocb *io = events[i].obj;
 
261
 
 
262
                if (filter->mode & TD_INJECT_FAULTS) {
 
263
                        if (fault_injected(filter, io)) {
 
264
                                recover_fault(filter, io);
 
265
                                continue;
 
266
                        }
 
267
                }
 
268
 
 
269
                if (filter->mode & TD_CHECK_INTEGRITY)
 
270
                        check_data(filter, POST_CHECK, io);
 
271
        }
 
272
}