xref: /openbmc/linux/drivers/md/dm-flakey.c (revision 3407ef5262b55ca5d7139d2b555ef792fe531eec)
1*3407ef52SJosef Bacik /*
2*3407ef52SJosef Bacik  * Copyright (C) 2003 Sistina Software (UK) Limited.
3*3407ef52SJosef Bacik  * Copyright (C) 2004, 2010 Red Hat, Inc. All rights reserved.
4*3407ef52SJosef Bacik  *
5*3407ef52SJosef Bacik  * This file is released under the GPL.
6*3407ef52SJosef Bacik  */
7*3407ef52SJosef Bacik 
8*3407ef52SJosef Bacik #include <linux/device-mapper.h>
9*3407ef52SJosef Bacik 
10*3407ef52SJosef Bacik #include <linux/module.h>
11*3407ef52SJosef Bacik #include <linux/init.h>
12*3407ef52SJosef Bacik #include <linux/blkdev.h>
13*3407ef52SJosef Bacik #include <linux/bio.h>
14*3407ef52SJosef Bacik #include <linux/slab.h>
15*3407ef52SJosef Bacik 
16*3407ef52SJosef Bacik #define DM_MSG_PREFIX "flakey"
17*3407ef52SJosef Bacik 
18*3407ef52SJosef Bacik /*
19*3407ef52SJosef Bacik  * Flakey: Used for testing only, simulates intermittent,
20*3407ef52SJosef Bacik  * catastrophic device failure.
21*3407ef52SJosef Bacik  */
22*3407ef52SJosef Bacik struct flakey_c {
23*3407ef52SJosef Bacik 	struct dm_dev *dev;
24*3407ef52SJosef Bacik 	unsigned long start_time;
25*3407ef52SJosef Bacik 	sector_t start;
26*3407ef52SJosef Bacik 	unsigned up_interval;
27*3407ef52SJosef Bacik 	unsigned down_interval;
28*3407ef52SJosef Bacik };
29*3407ef52SJosef Bacik 
30*3407ef52SJosef Bacik /*
31*3407ef52SJosef Bacik  * Construct a flakey mapping: <dev_path> <offset> <up interval> <down interval>
32*3407ef52SJosef Bacik  */
33*3407ef52SJosef Bacik static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv)
34*3407ef52SJosef Bacik {
35*3407ef52SJosef Bacik 	struct flakey_c *fc;
36*3407ef52SJosef Bacik 	unsigned long long tmp;
37*3407ef52SJosef Bacik 
38*3407ef52SJosef Bacik 	if (argc != 4) {
39*3407ef52SJosef Bacik 		ti->error = "dm-flakey: Invalid argument count";
40*3407ef52SJosef Bacik 		return -EINVAL;
41*3407ef52SJosef Bacik 	}
42*3407ef52SJosef Bacik 
43*3407ef52SJosef Bacik 	fc = kmalloc(sizeof(*fc), GFP_KERNEL);
44*3407ef52SJosef Bacik 	if (!fc) {
45*3407ef52SJosef Bacik 		ti->error = "dm-flakey: Cannot allocate linear context";
46*3407ef52SJosef Bacik 		return -ENOMEM;
47*3407ef52SJosef Bacik 	}
48*3407ef52SJosef Bacik 	fc->start_time = jiffies;
49*3407ef52SJosef Bacik 
50*3407ef52SJosef Bacik 	if (sscanf(argv[1], "%llu", &tmp) != 1) {
51*3407ef52SJosef Bacik 		ti->error = "dm-flakey: Invalid device sector";
52*3407ef52SJosef Bacik 		goto bad;
53*3407ef52SJosef Bacik 	}
54*3407ef52SJosef Bacik 	fc->start = tmp;
55*3407ef52SJosef Bacik 
56*3407ef52SJosef Bacik 	if (sscanf(argv[2], "%u", &fc->up_interval) != 1) {
57*3407ef52SJosef Bacik 		ti->error = "dm-flakey: Invalid up interval";
58*3407ef52SJosef Bacik 		goto bad;
59*3407ef52SJosef Bacik 	}
60*3407ef52SJosef Bacik 
61*3407ef52SJosef Bacik 	if (sscanf(argv[3], "%u", &fc->down_interval) != 1) {
62*3407ef52SJosef Bacik 		ti->error = "dm-flakey: Invalid down interval";
63*3407ef52SJosef Bacik 		goto bad;
64*3407ef52SJosef Bacik 	}
65*3407ef52SJosef Bacik 
66*3407ef52SJosef Bacik 	if (!(fc->up_interval + fc->down_interval)) {
67*3407ef52SJosef Bacik 		ti->error = "dm-flakey: Total (up + down) interval is zero";
68*3407ef52SJosef Bacik 		goto bad;
69*3407ef52SJosef Bacik 	}
70*3407ef52SJosef Bacik 
71*3407ef52SJosef Bacik 	if (fc->up_interval + fc->down_interval < fc->up_interval) {
72*3407ef52SJosef Bacik 		ti->error = "dm-flakey: Interval overflow";
73*3407ef52SJosef Bacik 		goto bad;
74*3407ef52SJosef Bacik 	}
75*3407ef52SJosef Bacik 
76*3407ef52SJosef Bacik 	if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &fc->dev)) {
77*3407ef52SJosef Bacik 		ti->error = "dm-flakey: Device lookup failed";
78*3407ef52SJosef Bacik 		goto bad;
79*3407ef52SJosef Bacik 	}
80*3407ef52SJosef Bacik 
81*3407ef52SJosef Bacik 	ti->num_flush_requests = 1;
82*3407ef52SJosef Bacik 	ti->private = fc;
83*3407ef52SJosef Bacik 	return 0;
84*3407ef52SJosef Bacik 
85*3407ef52SJosef Bacik bad:
86*3407ef52SJosef Bacik 	kfree(fc);
87*3407ef52SJosef Bacik 	return -EINVAL;
88*3407ef52SJosef Bacik }
89*3407ef52SJosef Bacik 
90*3407ef52SJosef Bacik static void flakey_dtr(struct dm_target *ti)
91*3407ef52SJosef Bacik {
92*3407ef52SJosef Bacik 	struct flakey_c *fc = ti->private;
93*3407ef52SJosef Bacik 
94*3407ef52SJosef Bacik 	dm_put_device(ti, fc->dev);
95*3407ef52SJosef Bacik 	kfree(fc);
96*3407ef52SJosef Bacik }
97*3407ef52SJosef Bacik 
98*3407ef52SJosef Bacik static sector_t flakey_map_sector(struct dm_target *ti, sector_t bi_sector)
99*3407ef52SJosef Bacik {
100*3407ef52SJosef Bacik 	struct flakey_c *fc = ti->private;
101*3407ef52SJosef Bacik 
102*3407ef52SJosef Bacik 	return fc->start + (bi_sector - ti->begin);
103*3407ef52SJosef Bacik }
104*3407ef52SJosef Bacik 
105*3407ef52SJosef Bacik static void flakey_map_bio(struct dm_target *ti, struct bio *bio)
106*3407ef52SJosef Bacik {
107*3407ef52SJosef Bacik 	struct flakey_c *fc = ti->private;
108*3407ef52SJosef Bacik 
109*3407ef52SJosef Bacik 	bio->bi_bdev = fc->dev->bdev;
110*3407ef52SJosef Bacik 	if (bio_sectors(bio))
111*3407ef52SJosef Bacik 		bio->bi_sector = flakey_map_sector(ti, bio->bi_sector);
112*3407ef52SJosef Bacik }
113*3407ef52SJosef Bacik 
114*3407ef52SJosef Bacik static int flakey_map(struct dm_target *ti, struct bio *bio,
115*3407ef52SJosef Bacik 		      union map_info *map_context)
116*3407ef52SJosef Bacik {
117*3407ef52SJosef Bacik 	struct flakey_c *fc = ti->private;
118*3407ef52SJosef Bacik 	unsigned elapsed;
119*3407ef52SJosef Bacik 
120*3407ef52SJosef Bacik 	/* Are we alive ? */
121*3407ef52SJosef Bacik 	elapsed = (jiffies - fc->start_time) / HZ;
122*3407ef52SJosef Bacik 	if (elapsed % (fc->up_interval + fc->down_interval) >= fc->up_interval)
123*3407ef52SJosef Bacik 		return -EIO;
124*3407ef52SJosef Bacik 
125*3407ef52SJosef Bacik 	flakey_map_bio(ti, bio);
126*3407ef52SJosef Bacik 
127*3407ef52SJosef Bacik 	return DM_MAPIO_REMAPPED;
128*3407ef52SJosef Bacik }
129*3407ef52SJosef Bacik 
130*3407ef52SJosef Bacik static int flakey_status(struct dm_target *ti, status_type_t type,
131*3407ef52SJosef Bacik 			 char *result, unsigned int maxlen)
132*3407ef52SJosef Bacik {
133*3407ef52SJosef Bacik 	struct flakey_c *fc = ti->private;
134*3407ef52SJosef Bacik 
135*3407ef52SJosef Bacik 	switch (type) {
136*3407ef52SJosef Bacik 	case STATUSTYPE_INFO:
137*3407ef52SJosef Bacik 		result[0] = '\0';
138*3407ef52SJosef Bacik 		break;
139*3407ef52SJosef Bacik 
140*3407ef52SJosef Bacik 	case STATUSTYPE_TABLE:
141*3407ef52SJosef Bacik 		snprintf(result, maxlen, "%s %llu %u %u", fc->dev->name,
142*3407ef52SJosef Bacik 			 (unsigned long long)fc->start, fc->up_interval,
143*3407ef52SJosef Bacik 			 fc->down_interval);
144*3407ef52SJosef Bacik 		break;
145*3407ef52SJosef Bacik 	}
146*3407ef52SJosef Bacik 	return 0;
147*3407ef52SJosef Bacik }
148*3407ef52SJosef Bacik 
149*3407ef52SJosef Bacik static int flakey_ioctl(struct dm_target *ti, unsigned int cmd, unsigned long arg)
150*3407ef52SJosef Bacik {
151*3407ef52SJosef Bacik 	struct flakey_c *fc = ti->private;
152*3407ef52SJosef Bacik 
153*3407ef52SJosef Bacik 	return __blkdev_driver_ioctl(fc->dev->bdev, fc->dev->mode, cmd, arg);
154*3407ef52SJosef Bacik }
155*3407ef52SJosef Bacik 
156*3407ef52SJosef Bacik static int flakey_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
157*3407ef52SJosef Bacik 			struct bio_vec *biovec, int max_size)
158*3407ef52SJosef Bacik {
159*3407ef52SJosef Bacik 	struct flakey_c *fc = ti->private;
160*3407ef52SJosef Bacik 	struct request_queue *q = bdev_get_queue(fc->dev->bdev);
161*3407ef52SJosef Bacik 
162*3407ef52SJosef Bacik 	if (!q->merge_bvec_fn)
163*3407ef52SJosef Bacik 		return max_size;
164*3407ef52SJosef Bacik 
165*3407ef52SJosef Bacik 	bvm->bi_bdev = fc->dev->bdev;
166*3407ef52SJosef Bacik 	bvm->bi_sector = flakey_map_sector(ti, bvm->bi_sector);
167*3407ef52SJosef Bacik 
168*3407ef52SJosef Bacik 	return min(max_size, q->merge_bvec_fn(q, bvm, biovec));
169*3407ef52SJosef Bacik }
170*3407ef52SJosef Bacik 
171*3407ef52SJosef Bacik static int flakey_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn, void *data)
172*3407ef52SJosef Bacik {
173*3407ef52SJosef Bacik 	struct flakey_c *fc = ti->private;
174*3407ef52SJosef Bacik 
175*3407ef52SJosef Bacik 	return fn(ti, fc->dev, fc->start, ti->len, data);
176*3407ef52SJosef Bacik }
177*3407ef52SJosef Bacik 
178*3407ef52SJosef Bacik static struct target_type flakey_target = {
179*3407ef52SJosef Bacik 	.name   = "flakey",
180*3407ef52SJosef Bacik 	.version = {1, 1, 0},
181*3407ef52SJosef Bacik 	.module = THIS_MODULE,
182*3407ef52SJosef Bacik 	.ctr    = flakey_ctr,
183*3407ef52SJosef Bacik 	.dtr    = flakey_dtr,
184*3407ef52SJosef Bacik 	.map    = flakey_map,
185*3407ef52SJosef Bacik 	.status = flakey_status,
186*3407ef52SJosef Bacik 	.ioctl	= flakey_ioctl,
187*3407ef52SJosef Bacik 	.merge	= flakey_merge,
188*3407ef52SJosef Bacik 	.iterate_devices = flakey_iterate_devices,
189*3407ef52SJosef Bacik };
190*3407ef52SJosef Bacik 
191*3407ef52SJosef Bacik static int __init dm_flakey_init(void)
192*3407ef52SJosef Bacik {
193*3407ef52SJosef Bacik 	int r = dm_register_target(&flakey_target);
194*3407ef52SJosef Bacik 
195*3407ef52SJosef Bacik 	if (r < 0)
196*3407ef52SJosef Bacik 		DMERR("register failed %d", r);
197*3407ef52SJosef Bacik 
198*3407ef52SJosef Bacik 	return r;
199*3407ef52SJosef Bacik }
200*3407ef52SJosef Bacik 
201*3407ef52SJosef Bacik static void __exit dm_flakey_exit(void)
202*3407ef52SJosef Bacik {
203*3407ef52SJosef Bacik 	dm_unregister_target(&flakey_target);
204*3407ef52SJosef Bacik }
205*3407ef52SJosef Bacik 
206*3407ef52SJosef Bacik /* Module hooks */
207*3407ef52SJosef Bacik module_init(dm_flakey_init);
208*3407ef52SJosef Bacik module_exit(dm_flakey_exit);
209*3407ef52SJosef Bacik 
210*3407ef52SJosef Bacik MODULE_DESCRIPTION(DM_NAME " flakey target");
211*3407ef52SJosef Bacik MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>");
212*3407ef52SJosef Bacik MODULE_LICENSE("GPL");
213