ia64/xen-unstable

view tools/xenstore/xs_crashme.c @ 6946:e703abaf6e3d

Add behaviour to the remove methods to remove the transaction's path itself. This allows us to write Remove(path) to remove the specified path rather than having to slice the path ourselves.
author emellor@ewan
date Sun Sep 18 14:42:13 2005 +0100 (2005-09-18)
parents 3233e7ecfa9f
children f7a7f8f2e6e4 872cf6ee0594
line source
1 /* Code which randomly corrupts bits going to the daemon.
2 Copyright (C) 2005 Rusty Russell IBM Corporation
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 #include <stdbool.h>
19 #include <stdio.h>
20 #include <sys/types.h>
21 #include <stdarg.h>
22 #include <string.h>
23 #include <sys/time.h>
24 #include "xs.h"
25 #include "talloc.h"
26 #include <errno.h>
27 #include "xenstored.h"
29 #define XSTEST
30 #define RAND_FREQ 128 /* One char in 32 is corrupted. */
32 /* jhash.h: Jenkins hash support.
33 *
34 * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net)
35 *
36 * http://burtleburtle.net/bob/hash/
37 *
38 * These are the credits from Bob's sources:
39 *
40 * lookup2.c, by Bob Jenkins, December 1996, Public Domain.
41 * hash(), hash2(), hash3, and mix() are externally useful functions.
42 * Routines to test the hash are included if SELF_TEST is defined.
43 * You can use this free for any purpose. It has no warranty.
44 *
45 * Copyright (C) 2003 David S. Miller (davem@redhat.com)
46 *
47 * I've modified Bob's hash to be useful in the Linux kernel, and
48 * any bugs present are surely my fault. -DaveM
49 */
51 /* NOTE: Arguments are modified. */
52 #define __jhash_mix(a, b, c) \
53 { \
54 a -= b; a -= c; a ^= (c>>13); \
55 b -= c; b -= a; b ^= (a<<8); \
56 c -= a; c -= b; c ^= (b>>13); \
57 a -= b; a -= c; a ^= (c>>12); \
58 b -= c; b -= a; b ^= (a<<16); \
59 c -= a; c -= b; c ^= (b>>5); \
60 a -= b; a -= c; a ^= (c>>3); \
61 b -= c; b -= a; b ^= (a<<10); \
62 c -= a; c -= b; c ^= (b>>15); \
63 }
65 /* The golden ration: an arbitrary value */
66 #define JHASH_GOLDEN_RATIO 0x9e3779b9
68 /* The most generic version, hashes an arbitrary sequence
69 * of bytes. No alignment or length assumptions are made about
70 * the input key.
71 */
72 static inline u32 jhash(const void *key, u32 length, u32 initval)
73 {
74 u32 a, b, c, len;
75 const u8 *k = key;
77 len = length;
78 a = b = JHASH_GOLDEN_RATIO;
79 c = initval;
81 while (len >= 12) {
82 a += (k[0] +((u32)k[1]<<8) +((u32)k[2]<<16) +((u32)k[3]<<24));
83 b += (k[4] +((u32)k[5]<<8) +((u32)k[6]<<16) +((u32)k[7]<<24));
84 c += (k[8] +((u32)k[9]<<8) +((u32)k[10]<<16)+((u32)k[11]<<24));
86 __jhash_mix(a,b,c);
88 k += 12;
89 len -= 12;
90 }
92 c += length;
93 switch (len) {
94 case 11: c += ((u32)k[10]<<24);
95 case 10: c += ((u32)k[9]<<16);
96 case 9 : c += ((u32)k[8]<<8);
97 case 8 : b += ((u32)k[7]<<24);
98 case 7 : b += ((u32)k[6]<<16);
99 case 6 : b += ((u32)k[5]<<8);
100 case 5 : b += k[4];
101 case 4 : a += ((u32)k[3]<<24);
102 case 3 : a += ((u32)k[2]<<16);
103 case 2 : a += ((u32)k[1]<<8);
104 case 1 : a += k[0];
105 };
107 __jhash_mix(a,b,c);
109 return c;
110 }
112 /* A special optimized version that handles 1 or more of u32s.
113 * The length parameter here is the number of u32s in the key.
114 */
115 static inline u32 jhash2(u32 *k, u32 length, u32 initval)
116 {
117 u32 a, b, c, len;
119 a = b = JHASH_GOLDEN_RATIO;
120 c = initval;
121 len = length;
123 while (len >= 3) {
124 a += k[0];
125 b += k[1];
126 c += k[2];
127 __jhash_mix(a, b, c);
128 k += 3; len -= 3;
129 }
131 c += length * 4;
133 switch (len) {
134 case 2 : b += k[1];
135 case 1 : a += k[0];
136 };
138 __jhash_mix(a,b,c);
140 return c;
141 }
144 /* A special ultra-optimized versions that knows they are hashing exactly
145 * 3, 2 or 1 word(s).
146 *
147 * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally
148 * done at the end is not done here.
149 */
150 static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval)
151 {
152 a += JHASH_GOLDEN_RATIO;
153 b += JHASH_GOLDEN_RATIO;
154 c += initval;
156 __jhash_mix(a, b, c);
158 return c;
159 }
161 static inline u32 jhash_2words(u32 a, u32 b, u32 initval)
162 {
163 return jhash_3words(a, b, 0, initval);
164 }
166 static inline u32 jhash_1word(u32 a, u32 initval)
167 {
168 return jhash_3words(a, 0, 0, initval);
169 }
171 static unsigned int get_randomness(int *state)
172 {
173 return jhash_1word((*state)++, *state * 1103515243);
174 }
176 static int state;
178 /* Lengthening headers is pointless: other end will just wait for more
179 * data and timeout. We merely shorten the length. */
180 static void corrupt_header(char *output, const struct xsd_sockmsg *msg,
181 unsigned int *next_bit)
182 {
183 struct xsd_sockmsg newmsg = *msg;
185 while (*next_bit < sizeof(*msg)) {
186 if (newmsg.len)
187 newmsg.len = get_randomness(&state) % newmsg.len;
188 *next_bit += get_randomness(&state) % RAND_FREQ;
189 }
190 memcpy(output, &newmsg, sizeof(newmsg));
191 }
193 #define read_all_choice read_all
194 static bool write_all_choice(int fd, const void *data, unsigned int len)
195 {
196 char corrupt_data[len];
197 bool ret;
198 static unsigned int next_bit;
200 if (len == sizeof(struct xsd_sockmsg)
201 && ((unsigned long)data % __alignof__(struct xsd_sockmsg)) == 0)
202 corrupt_header(corrupt_data, data, &next_bit);
203 else {
204 memcpy(corrupt_data, data, len);
205 while (next_bit < len * CHAR_BIT) {
206 corrupt_data[next_bit/CHAR_BIT]
207 ^= (1 << (next_bit%CHAR_BIT));
208 next_bit += get_randomness(&state) % RAND_FREQ;
209 }
210 }
212 ret = xs_write_all(fd, corrupt_data, len);
213 next_bit -= len * CHAR_BIT;
214 return ret;
215 }
217 #include "xs.c"
219 static char *random_path(void)
220 {
221 unsigned int i;
222 char *ret = NULL;
224 if (get_randomness(&state) % 20 == 0)
225 return talloc_strdup(NULL, "/");
227 for (i = 0; i < 1 || (get_randomness(&state) % 2); i++) {
228 ret = talloc_asprintf_append(ret, "/%i",
229 get_randomness(&state) % 15);
230 }
231 return ret;
232 }
234 static int random_flags(int *state)
235 {
236 switch (get_randomness(state) % 4) {
237 case 0:
238 return 0;
239 case 1:
240 return O_CREAT;
241 case 2:
242 return O_CREAT|O_EXCL;
243 default:
244 return get_randomness(state);
245 }
246 }
248 /* Do the next operation, return the results. */
249 static void do_next_op(struct xs_handle *h, bool verbose)
250 {
251 char *name;
252 unsigned int num;
254 if (verbose)
255 printf("State %i: ", state);
257 name = random_path();
258 switch (get_randomness(&state) % 9) {
259 case 0:
260 if (verbose)
261 printf("DIR %s\n", name);
262 free(xs_directory(h, name, &num));
263 break;
264 case 1:
265 if (verbose)
266 printf("READ %s\n", name);
267 free(xs_read(h, name, &num));
268 break;
269 case 2: {
270 int flags = random_flags(&state);
271 char *contents = talloc_asprintf(NULL, "%i",
272 get_randomness(&state));
273 unsigned int len = get_randomness(&state)%(strlen(contents)+1);
274 if (verbose)
275 printf("WRITE %s %s %.*s\n", name,
276 flags == O_CREAT ? "O_CREAT"
277 : flags == (O_CREAT|O_EXCL) ? "O_CREAT|O_EXCL"
278 : flags == 0 ? "0" : "CRAPFLAGS",
279 len, contents);
280 xs_write(h, name, contents, len, flags);
281 break;
282 }
283 case 3:
284 if (verbose)
285 printf("MKDIR %s\n", name);
286 xs_mkdir(h, name);
287 break;
288 case 4:
289 if (verbose)
290 printf("RM %s\n", name);
291 xs_rm(h, name);
292 break;
293 case 5:
294 if (verbose)
295 printf("GETPERMS %s\n", name);
296 free(xs_get_permissions(h, name, &num));
297 break;
298 case 6: {
299 unsigned int i, num = get_randomness(&state)%8;
300 struct xs_permissions perms[num];
302 if (verbose)
303 printf("SETPERMS %s: ", name);
304 for (i = 0; i < num; i++) {
305 perms[i].id = get_randomness(&state)%8;
306 perms[i].perms = get_randomness(&state)%4;
307 if (verbose)
308 printf("%i%c ", perms[i].id,
309 perms[i].perms == XS_PERM_WRITE ? 'W'
310 : perms[i].perms == XS_PERM_READ ? 'R'
311 : perms[i].perms ==
312 (XS_PERM_READ|XS_PERM_WRITE) ? 'B'
313 : 'N');
314 }
315 if (verbose)
316 printf("\n");
317 xs_set_permissions(h, name, perms, num);
318 break;
319 }
320 case 7: {
321 if (verbose)
322 printf("START %s\n", name);
323 xs_transaction_start(h, name);
324 break;
325 }
326 case 8: {
327 bool abort = (get_randomness(&state) % 2);
329 if (verbose)
330 printf("STOP %s\n", abort ? "ABORT" : "COMMIT");
331 xs_transaction_end(h, abort);
332 break;
333 }
334 default:
335 barf("Impossible randomness");
336 }
337 }
339 static struct xs_handle *h;
340 static void alarmed(int sig __attribute__((unused)))
341 {
342 /* We force close on timeout. */
343 close(h->fd);
344 }
346 static int start_daemon(void)
347 {
348 int fds[2];
349 int daemon_pid;
351 /* Start daemon. */
352 pipe(fds);
353 if ((daemon_pid = fork())) {
354 /* Child writes PID when its ready: we wait for that. */
355 char buffer[20];
356 close(fds[1]);
357 if (read(fds[0], buffer, sizeof(buffer)) < 0)
358 barf("Failed to summon daemon");
359 close(fds[0]);
360 return daemon_pid;
361 } else {
362 dup2(fds[1], STDOUT_FILENO);
363 close(fds[0]);
364 #if 1
365 execlp("valgrind", "valgrind", "--log-file=/tmp/xs_crashme.vglog", "-q", "./xenstored_test", "--output-pid",
366 "--no-fork", "--trace-file=/tmp/trace", NULL);
367 #else
368 execlp("./xenstored_test", "xenstored_test", "--output-pid",
369 "--no-fork", NULL);
370 #endif
371 exit(1);
372 }
373 }
376 int main(int argc, char **argv)
377 {
378 unsigned int i;
379 int pid;
381 if (argc != 3 && argc != 4)
382 barf("Usage: xs_crashme <iterations> <seed> [pid]");
384 if (argc == 3)
385 pid = start_daemon();
386 else
387 pid = atoi(argv[3]);
389 state = atoi(argv[2]);
390 h = xs_daemon_open();
391 if (!h)
392 barf_perror("Opening connection to daemon");
393 signal(SIGALRM, alarmed);
394 for (i = 0; i < (unsigned)atoi(argv[1]); i++) {
395 alarm(1);
396 do_next_op(h, false);
397 if (i % (atoi(argv[1]) / 72 ?: 1) == 0) {
398 printf(".");
399 fflush(stdout);
400 }
401 if (kill(pid, 0) != 0)
402 barf_perror("Pinging daemon on iteration %i", i);
403 if (h->fd < 0) {
404 xs_daemon_close(h);
405 h = xs_daemon_open();
406 if (!h)
407 barf_perror("Connecting on iteration %i", i);
408 }
409 }
410 kill(pid, SIGTERM);
411 return 0;
412 }