ia64/xen-unstable

view tools/xenstore/xs_crashme.c @ 7238:971e7c7411b3

Raise an exception if an error appears on the pipes to our children, and make
sure that the child's pipes are closed even under that exception. Move the
handling of POLLHUP to the end of the loop, so that we guarantee to read any
remaining data from the child if POLLHUP and POLLIN appear at the same time.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author emellor@ewan
date Thu Oct 06 10:13:11 2005 +0100 (2005-10-06)
parents 06d84bf87159
children 62d815160f01
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 char *contents = talloc_asprintf(NULL, "%i",
271 get_randomness(&state));
272 unsigned int len = get_randomness(&state)%(strlen(contents)+1);
273 if (verbose)
274 printf("WRITE %s %.*s\n", name, len, contents);
275 xs_write(h, name, contents, len);
276 break;
277 }
278 case 3:
279 if (verbose)
280 printf("MKDIR %s\n", name);
281 xs_mkdir(h, name);
282 break;
283 case 4:
284 if (verbose)
285 printf("RM %s\n", name);
286 xs_rm(h, name);
287 break;
288 case 5:
289 if (verbose)
290 printf("GETPERMS %s\n", name);
291 free(xs_get_permissions(h, name, &num));
292 break;
293 case 6: {
294 unsigned int i, num = get_randomness(&state)%8;
295 struct xs_permissions perms[num];
297 if (verbose)
298 printf("SETPERMS %s: ", name);
299 for (i = 0; i < num; i++) {
300 perms[i].id = get_randomness(&state)%8;
301 perms[i].perms = get_randomness(&state)%4;
302 if (verbose)
303 printf("%i%c ", perms[i].id,
304 perms[i].perms == XS_PERM_WRITE ? 'W'
305 : perms[i].perms == XS_PERM_READ ? 'R'
306 : perms[i].perms ==
307 (XS_PERM_READ|XS_PERM_WRITE) ? 'B'
308 : 'N');
309 }
310 if (verbose)
311 printf("\n");
312 xs_set_permissions(h, name, perms, num);
313 break;
314 }
315 case 7: {
316 if (verbose)
317 printf("START %s\n", name);
318 xs_transaction_start(h, name);
319 break;
320 }
321 case 8: {
322 bool abort = (get_randomness(&state) % 2);
324 if (verbose)
325 printf("STOP %s\n", abort ? "ABORT" : "COMMIT");
326 xs_transaction_end(h, abort);
327 break;
328 }
329 default:
330 barf("Impossible randomness");
331 }
332 }
334 static struct xs_handle *h;
335 static void alarmed(int sig __attribute__((unused)))
336 {
337 /* We force close on timeout. */
338 close(h->fd);
339 }
341 static int start_daemon(void)
342 {
343 int fds[2];
344 int daemon_pid;
346 /* Start daemon. */
347 pipe(fds);
348 if ((daemon_pid = fork())) {
349 /* Child writes PID when its ready: we wait for that. */
350 char buffer[20];
351 close(fds[1]);
352 if (read(fds[0], buffer, sizeof(buffer)) < 0)
353 barf("Failed to summon daemon");
354 close(fds[0]);
355 return daemon_pid;
356 } else {
357 dup2(fds[1], STDOUT_FILENO);
358 close(fds[0]);
359 #if 1
360 execlp("valgrind", "valgrind", "--log-file=/tmp/xs_crashme.vglog", "-q", "./xenstored_test", "--output-pid",
361 "--no-fork", "--trace-file=/tmp/trace", NULL);
362 #else
363 execlp("./xenstored_test", "xenstored_test", "--output-pid",
364 "--no-fork", NULL);
365 #endif
366 exit(1);
367 }
368 }
371 int main(int argc, char **argv)
372 {
373 unsigned int i;
374 int pid;
376 if (argc != 3 && argc != 4)
377 barf("Usage: xs_crashme <iterations> <seed> [pid]");
379 if (argc == 3)
380 pid = start_daemon();
381 else
382 pid = atoi(argv[3]);
384 state = atoi(argv[2]);
385 h = xs_daemon_open();
386 if (!h)
387 barf_perror("Opening connection to daemon");
388 signal(SIGALRM, alarmed);
389 for (i = 0; i < (unsigned)atoi(argv[1]); i++) {
390 alarm(1);
391 do_next_op(h, false);
392 if (i % (atoi(argv[1]) / 72 ?: 1) == 0) {
393 printf(".");
394 fflush(stdout);
395 }
396 if (kill(pid, 0) != 0)
397 barf_perror("Pinging daemon on iteration %i", i);
398 if (h->fd < 0) {
399 xs_daemon_close(h);
400 h = xs_daemon_open();
401 if (!h)
402 barf_perror("Connecting on iteration %i", i);
403 }
404 }
405 kill(pid, SIGTERM);
406 return 0;
407 }