Introduce simple random fault injection. It is currently controlled
by setting RUMP_BLKFAIL to control the frequency and optionally RUMP_BLKFAIL_SEED, which seeds the "random" number generator. Feel free to extend the code if you want something "a little more" for your purposes.
This commit is contained in:
parent
a9ecd753f2
commit
fa73a97f70
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: rumpblk.c,v 1.2 2009/01/27 09:14:01 pooka Exp $ */
|
/* $NetBSD: rumpblk.c,v 1.3 2009/02/10 20:43:01 pooka Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2009 Antti Kantee. All Rights Reserved.
|
* Copyright (c) 2009 Antti Kantee. All Rights Reserved.
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__KERNEL_RCSID(0, "$NetBSD: rumpblk.c,v 1.2 2009/01/27 09:14:01 pooka Exp $");
|
__KERNEL_RCSID(0, "$NetBSD: rumpblk.c,v 1.3 2009/02/10 20:43:01 pooka Exp $");
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/buf.h>
|
#include <sys/buf.h>
|
||||||
|
@ -66,6 +66,7 @@ dev_type_read(rumpblk_read);
|
||||||
dev_type_write(rumpblk_write);
|
dev_type_write(rumpblk_write);
|
||||||
dev_type_ioctl(rumpblk_ioctl);
|
dev_type_ioctl(rumpblk_ioctl);
|
||||||
dev_type_strategy(rumpblk_strategy);
|
dev_type_strategy(rumpblk_strategy);
|
||||||
|
dev_type_strategy(rumpblk_strategy_fail);
|
||||||
dev_type_dump(rumpblk_dump);
|
dev_type_dump(rumpblk_dump);
|
||||||
dev_type_size(rumpblk_size);
|
dev_type_size(rumpblk_size);
|
||||||
|
|
||||||
|
@ -74,20 +75,53 @@ static const struct bdevsw rumpblk_bdevsw = {
|
||||||
nodump, nosize, D_DISK
|
nodump, nosize, D_DISK
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct bdevsw rumpblk_bdevsw_fail = {
|
||||||
|
rumpblk_open, rumpblk_close, rumpblk_strategy_fail, rumpblk_ioctl,
|
||||||
|
nodump, nosize, D_DISK
|
||||||
|
};
|
||||||
|
|
||||||
static const struct cdevsw rumpblk_cdevsw = {
|
static const struct cdevsw rumpblk_cdevsw = {
|
||||||
rumpblk_open, rumpblk_close, rumpblk_read, rumpblk_write,
|
rumpblk_open, rumpblk_close, rumpblk_read, rumpblk_write,
|
||||||
rumpblk_ioctl, nostop, notty, nopoll, nommap, nokqfilter, D_DISK
|
rumpblk_ioctl, nostop, notty, nopoll, nommap, nokqfilter, D_DISK
|
||||||
};
|
};
|
||||||
|
|
||||||
/* XXX: not mpsafe */
|
/* fail every n out of BLKFAIL_MAX */
|
||||||
|
#define BLKFAIL_MAX 10000
|
||||||
|
static int blkfail;
|
||||||
|
static unsigned randstate;
|
||||||
|
|
||||||
int
|
int
|
||||||
rumpblk_init()
|
rumpblk_init()
|
||||||
{
|
{
|
||||||
|
char buf[64];
|
||||||
int rumpblk = RUMPBLK;
|
int rumpblk = RUMPBLK;
|
||||||
|
int error;
|
||||||
|
|
||||||
return devsw_attach("rumpblk", &rumpblk_bdevsw, &rumpblk,
|
if (rumpuser_getenv("RUMP_BLKFAIL", buf, sizeof(buf), &error) == 0) {
|
||||||
&rumpblk_cdevsw, &rumpblk);
|
blkfail = strtoul(buf, NULL, 10);
|
||||||
|
/* fail everything */
|
||||||
|
if (blkfail > BLKFAIL_MAX)
|
||||||
|
blkfail = BLKFAIL_MAX;
|
||||||
|
if (rumpuser_getenv("RUMP_BLKFAIL_SEED", buf, sizeof(buf),
|
||||||
|
&error) == 0) {
|
||||||
|
randstate = strtoul(buf, NULL, 10);
|
||||||
|
} else {
|
||||||
|
randstate = arc4random(); /* XXX: not enough entropy */
|
||||||
|
}
|
||||||
|
printf("rumpblk: FAULT INJECTION ACTIVE! every %d out of"
|
||||||
|
" %d I/O will fail. key %u\n", blkfail, BLKFAIL_MAX,
|
||||||
|
randstate);
|
||||||
|
} else {
|
||||||
|
blkfail = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blkfail) {
|
||||||
|
return devsw_attach("rumpblk", &rumpblk_bdevsw_fail, &rumpblk,
|
||||||
|
&rumpblk_cdevsw, &rumpblk);
|
||||||
|
} else {
|
||||||
|
return devsw_attach("rumpblk", &rumpblk_bdevsw, &rumpblk,
|
||||||
|
&rumpblk_cdevsw, &rumpblk);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -203,8 +237,8 @@ rumpblk_write(dev_t dev, struct uio *uio, int flags)
|
||||||
panic("%s: unimplemented", __func__);
|
panic("%s: unimplemented", __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
rumpblk_strategy(struct buf *bp)
|
dostrategy(struct buf *bp)
|
||||||
{
|
{
|
||||||
struct rblkdev *rblk = &minors[minor(bp->b_dev)];
|
struct rblkdev *rblk = &minors[minor(bp->b_dev)];
|
||||||
off_t off;
|
off_t off;
|
||||||
|
@ -278,3 +312,40 @@ rumpblk_strategy(struct buf *bp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rumpblk_strategy(struct buf *bp)
|
||||||
|
{
|
||||||
|
|
||||||
|
dostrategy(bp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* <mlelstv> pooka, rand()
|
||||||
|
* <mlelstv> [paste]
|
||||||
|
*/
|
||||||
|
static unsigned
|
||||||
|
gimmerand(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
return (randstate = randstate * 1103515245 + 12345) % (0x80000000L);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Block device with very simple fault injection. Fails every
|
||||||
|
* n out of BLKFAIL_MAX I/O with EIO. n is determined by the env
|
||||||
|
* variable RUMP_BLKFAIL.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
rumpblk_strategy_fail(struct buf *bp)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (gimmerand() % BLKFAIL_MAX >= blkfail) {
|
||||||
|
dostrategy(bp);
|
||||||
|
} else {
|
||||||
|
printf("block fault injection: failing I/O on block %lld\n",
|
||||||
|
(long long)bp->b_blkno);
|
||||||
|
bp->b_error = EIO;
|
||||||
|
biodone(bp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue