xref: /dflybsd-src/sys/dev/disk/dm/flakey/dm_target_flakey.c (revision f603807b2c8b9b8ca8a7a99e36eeb70cd39b460d)
1*f603807bSTomohiro Kusumi /*
2*f603807bSTomohiro Kusumi  * Copyright (c) 2015 The DragonFly Project.  All rights reserved.
3*f603807bSTomohiro Kusumi  *
4*f603807bSTomohiro Kusumi  * This code is derived from software contributed to The DragonFly Project
5*f603807bSTomohiro Kusumi  * by Tomohiro Kusumi <kusumi.tomohiro@gmail.com>
6*f603807bSTomohiro Kusumi  *
7*f603807bSTomohiro Kusumi  * Redistribution and use in source and binary forms, with or without
8*f603807bSTomohiro Kusumi  * modification, are permitted provided that the following conditions
9*f603807bSTomohiro Kusumi  * are met:
10*f603807bSTomohiro Kusumi  *
11*f603807bSTomohiro Kusumi  * 1. Redistributions of source code must retain the above copyright
12*f603807bSTomohiro Kusumi  *    notice, this list of conditions and the following disclaimer.
13*f603807bSTomohiro Kusumi  * 2. Redistributions in binary form must reproduce the above copyright
14*f603807bSTomohiro Kusumi  *    notice, this list of conditions and the following disclaimer in
15*f603807bSTomohiro Kusumi  *    the documentation and/or other materials provided with the
16*f603807bSTomohiro Kusumi  *    distribution.
17*f603807bSTomohiro Kusumi  * 3. Neither the name of The DragonFly Project nor the names of its
18*f603807bSTomohiro Kusumi  *    contributors may be used to endorse or promote products derived
19*f603807bSTomohiro Kusumi  *    from this software without specific, prior written permission.
20*f603807bSTomohiro Kusumi  *
21*f603807bSTomohiro Kusumi  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22*f603807bSTomohiro Kusumi  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23*f603807bSTomohiro Kusumi  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24*f603807bSTomohiro Kusumi  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25*f603807bSTomohiro Kusumi  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26*f603807bSTomohiro Kusumi  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27*f603807bSTomohiro Kusumi  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28*f603807bSTomohiro Kusumi  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29*f603807bSTomohiro Kusumi  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30*f603807bSTomohiro Kusumi  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31*f603807bSTomohiro Kusumi  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32*f603807bSTomohiro Kusumi  * SUCH DAMAGE.
33*f603807bSTomohiro Kusumi  */
34*f603807bSTomohiro Kusumi 
35*f603807bSTomohiro Kusumi #include <dev/disk/dm/dm.h>
36*f603807bSTomohiro Kusumi 
37*f603807bSTomohiro Kusumi MALLOC_DEFINE(M_DMFLAKEY, "dm_flakey", "Device Mapper Target Flakey");
38*f603807bSTomohiro Kusumi 
39*f603807bSTomohiro Kusumi /* dm_flakey never updates any field after initialization */
40*f603807bSTomohiro Kusumi typedef struct target_flakey_config {
41*f603807bSTomohiro Kusumi 	dm_pdev_t *pdev;
42*f603807bSTomohiro Kusumi 	uint64_t offset;
43*f603807bSTomohiro Kusumi 	int up_int;
44*f603807bSTomohiro Kusumi 	int down_int;
45*f603807bSTomohiro Kusumi 	int offset_time;
46*f603807bSTomohiro Kusumi 
47*f603807bSTomohiro Kusumi 	/* drop_writes feature */
48*f603807bSTomohiro Kusumi 	int drop_writes;
49*f603807bSTomohiro Kusumi 
50*f603807bSTomohiro Kusumi 	/* corrupt_bio_byte feature */
51*f603807bSTomohiro Kusumi 	unsigned int corrupt_buf_byte;
52*f603807bSTomohiro Kusumi 	unsigned int corrupt_buf_rw;
53*f603807bSTomohiro Kusumi 	unsigned int corrupt_buf_value;
54*f603807bSTomohiro Kusumi 	unsigned int corrupt_buf_flags;  /* for B_XXX flags */
55*f603807bSTomohiro Kusumi } dm_target_flakey_config_t;
56*f603807bSTomohiro Kusumi 
57*f603807bSTomohiro Kusumi #define FLAKEY_CORRUPT_DIR(tfc) \
58*f603807bSTomohiro Kusumi 	((tfc)->corrupt_buf_rw == BUF_CMD_READ ? 'r' : 'w')
59*f603807bSTomohiro Kusumi 
60*f603807bSTomohiro Kusumi static int _init_features(dm_target_flakey_config_t*, int, char**);
61*f603807bSTomohiro Kusumi static __inline void _submit(dm_target_flakey_config_t*, struct bio*);
62*f603807bSTomohiro Kusumi static int _flakey_read(dm_target_flakey_config_t*, struct buf*);
63*f603807bSTomohiro Kusumi static int _flakey_write(dm_target_flakey_config_t*, struct buf*);
64*f603807bSTomohiro Kusumi static int _flakey_corrupt_buf(dm_target_flakey_config_t*, struct bio*);
65*f603807bSTomohiro Kusumi 
66*f603807bSTomohiro Kusumi static int
67*f603807bSTomohiro Kusumi dm_target_flakey_init(dm_table_entry_t *table_en, int argc, char **argv)
68*f603807bSTomohiro Kusumi {
69*f603807bSTomohiro Kusumi 	dm_target_flakey_config_t *tfc;
70*f603807bSTomohiro Kusumi 	dm_pdev_t *dmp;
71*f603807bSTomohiro Kusumi 	int err;
72*f603807bSTomohiro Kusumi 
73*f603807bSTomohiro Kusumi 	dmdebug("Flakey target init: argc=%d\n", argc);
74*f603807bSTomohiro Kusumi 
75*f603807bSTomohiro Kusumi 	if (argc < 4) {
76*f603807bSTomohiro Kusumi 		kprintf("Flakey target takes 4 or more args\n");
77*f603807bSTomohiro Kusumi 		return EINVAL;
78*f603807bSTomohiro Kusumi 	}
79*f603807bSTomohiro Kusumi 
80*f603807bSTomohiro Kusumi 	tfc = kmalloc(sizeof(*tfc), M_DMFLAKEY, M_WAITOK | M_ZERO);
81*f603807bSTomohiro Kusumi 	if (tfc == NULL)
82*f603807bSTomohiro Kusumi 		return ENOMEM;
83*f603807bSTomohiro Kusumi 
84*f603807bSTomohiro Kusumi 	if ((dmp = dm_pdev_insert(argv[0])) == NULL) {
85*f603807bSTomohiro Kusumi 		err = ENOENT;
86*f603807bSTomohiro Kusumi 		goto fail;
87*f603807bSTomohiro Kusumi 	}
88*f603807bSTomohiro Kusumi 	tfc->pdev = dmp;
89*f603807bSTomohiro Kusumi 	tfc->offset = atoi64(argv[1]);
90*f603807bSTomohiro Kusumi 	tfc->up_int = atoi64(argv[2]);
91*f603807bSTomohiro Kusumi 	tfc->down_int = atoi64(argv[3]);
92*f603807bSTomohiro Kusumi 	tfc->offset_time = ticks;
93*f603807bSTomohiro Kusumi 
94*f603807bSTomohiro Kusumi 	if ((tfc->up_int + tfc->down_int) == 0) {
95*f603807bSTomohiro Kusumi 		kprintf("Sum of up/down interval is 0\n");
96*f603807bSTomohiro Kusumi 		err = EINVAL;
97*f603807bSTomohiro Kusumi 		goto fail;
98*f603807bSTomohiro Kusumi 	}
99*f603807bSTomohiro Kusumi 
100*f603807bSTomohiro Kusumi 	if (tfc->up_int + tfc->down_int < tfc->up_int) {
101*f603807bSTomohiro Kusumi 		kprintf("Interval time overflow\n");
102*f603807bSTomohiro Kusumi 		err = EINVAL;
103*f603807bSTomohiro Kusumi 		goto fail;
104*f603807bSTomohiro Kusumi 	}
105*f603807bSTomohiro Kusumi 
106*f603807bSTomohiro Kusumi 	err = _init_features(tfc, argc - 4, argv + 4);
107*f603807bSTomohiro Kusumi 	if (err)
108*f603807bSTomohiro Kusumi 		goto fail;
109*f603807bSTomohiro Kusumi 
110*f603807bSTomohiro Kusumi 	dm_table_add_deps(table_en, dmp);
111*f603807bSTomohiro Kusumi 
112*f603807bSTomohiro Kusumi 	dm_table_init_target(table_en, DM_FLAKEY_DEV, tfc);
113*f603807bSTomohiro Kusumi 
114*f603807bSTomohiro Kusumi 	return 0;
115*f603807bSTomohiro Kusumi fail:
116*f603807bSTomohiro Kusumi 	kfree(tfc, M_DMFLAKEY);
117*f603807bSTomohiro Kusumi 	return err;
118*f603807bSTomohiro Kusumi }
119*f603807bSTomohiro Kusumi 
120*f603807bSTomohiro Kusumi static int
121*f603807bSTomohiro Kusumi _init_features(dm_target_flakey_config_t *tfc, int argc, char **argv)
122*f603807bSTomohiro Kusumi {
123*f603807bSTomohiro Kusumi 	char *arg;
124*f603807bSTomohiro Kusumi 	unsigned int value;
125*f603807bSTomohiro Kusumi 
126*f603807bSTomohiro Kusumi 	if (argc == 0)
127*f603807bSTomohiro Kusumi 		return 0;
128*f603807bSTomohiro Kusumi 
129*f603807bSTomohiro Kusumi 	argc = atoi64(*argv++);  /* # of args for features */
130*f603807bSTomohiro Kusumi 	if (argc > 6) {
131*f603807bSTomohiro Kusumi 		kprintf("Invalid # of feature args %d\n", argc);
132*f603807bSTomohiro Kusumi 		return EINVAL;
133*f603807bSTomohiro Kusumi 	}
134*f603807bSTomohiro Kusumi 
135*f603807bSTomohiro Kusumi 	while (argc) {
136*f603807bSTomohiro Kusumi 		argc--;
137*f603807bSTomohiro Kusumi 		arg = *argv++;
138*f603807bSTomohiro Kusumi 
139*f603807bSTomohiro Kusumi 		/* drop_writes */
140*f603807bSTomohiro Kusumi 		if (strcmp(arg, "drop_writes") == 0) {
141*f603807bSTomohiro Kusumi 			tfc->drop_writes = 1;
142*f603807bSTomohiro Kusumi 			continue;
143*f603807bSTomohiro Kusumi 		}
144*f603807bSTomohiro Kusumi 
145*f603807bSTomohiro Kusumi 		/* corrupt_bio_byte <Nth_byte> <direction> <value> <flags> */
146*f603807bSTomohiro Kusumi 		if (strcmp(arg, "corrupt_bio_byte") == 0) {
147*f603807bSTomohiro Kusumi 			if (argc < 4) {
148*f603807bSTomohiro Kusumi 				kprintf("Invalid # of feature args %d for "
149*f603807bSTomohiro Kusumi 					"corrupt_bio_byte\n", argc);
150*f603807bSTomohiro Kusumi 				return EINVAL;
151*f603807bSTomohiro Kusumi 			}
152*f603807bSTomohiro Kusumi 
153*f603807bSTomohiro Kusumi 			/* <Nth_byte> */
154*f603807bSTomohiro Kusumi 			argc--;
155*f603807bSTomohiro Kusumi 			value = atoi64(*argv++);
156*f603807bSTomohiro Kusumi 			if (value < 1) {
157*f603807bSTomohiro Kusumi 				kprintf("Invalid corrupt_bio_byte "
158*f603807bSTomohiro Kusumi 					"<Nth_byte> arg %u\n", value);
159*f603807bSTomohiro Kusumi 				return EINVAL;
160*f603807bSTomohiro Kusumi 			}
161*f603807bSTomohiro Kusumi 			tfc->corrupt_buf_byte = value;
162*f603807bSTomohiro Kusumi 
163*f603807bSTomohiro Kusumi 			/* <direction> */
164*f603807bSTomohiro Kusumi 			argc--;
165*f603807bSTomohiro Kusumi 			arg = *argv++;
166*f603807bSTomohiro Kusumi 			if (strcmp(arg, "r") == 0) {
167*f603807bSTomohiro Kusumi 				tfc->corrupt_buf_rw = BUF_CMD_READ;
168*f603807bSTomohiro Kusumi 			} else if (strcmp(arg, "w") == 0) {
169*f603807bSTomohiro Kusumi 				tfc->corrupt_buf_rw = BUF_CMD_WRITE;
170*f603807bSTomohiro Kusumi 			} else {
171*f603807bSTomohiro Kusumi 				kprintf("Invalid corrupt_bio_byte "
172*f603807bSTomohiro Kusumi 					"<direction> arg %s\n", arg);
173*f603807bSTomohiro Kusumi 				return EINVAL;
174*f603807bSTomohiro Kusumi 			}
175*f603807bSTomohiro Kusumi 
176*f603807bSTomohiro Kusumi 			/* <value> */
177*f603807bSTomohiro Kusumi 			argc--;
178*f603807bSTomohiro Kusumi 			value = atoi64(*argv++);
179*f603807bSTomohiro Kusumi 			if (value > 0xff) {
180*f603807bSTomohiro Kusumi 				kprintf("Invalid corrupt_bio_byte "
181*f603807bSTomohiro Kusumi 					"<value> arg %u\n", value);
182*f603807bSTomohiro Kusumi 				return EINVAL;
183*f603807bSTomohiro Kusumi 			}
184*f603807bSTomohiro Kusumi 			tfc->corrupt_buf_value = value;
185*f603807bSTomohiro Kusumi 
186*f603807bSTomohiro Kusumi 			/* <flags> */
187*f603807bSTomohiro Kusumi 			argc--;
188*f603807bSTomohiro Kusumi 			tfc->corrupt_buf_flags = atoi64(*argv++);
189*f603807bSTomohiro Kusumi 
190*f603807bSTomohiro Kusumi 			continue;
191*f603807bSTomohiro Kusumi 		}
192*f603807bSTomohiro Kusumi 
193*f603807bSTomohiro Kusumi 		kprintf("Unknown Flakey target feature %s\n", arg);
194*f603807bSTomohiro Kusumi 		return EINVAL;
195*f603807bSTomohiro Kusumi 	}
196*f603807bSTomohiro Kusumi 
197*f603807bSTomohiro Kusumi 	if (tfc->drop_writes && (tfc->corrupt_buf_rw == BUF_CMD_WRITE)) {
198*f603807bSTomohiro Kusumi 		kprintf("Flakey target doesn't allow drop_writes feature "
199*f603807bSTomohiro Kusumi 			"and corrupt_bio_byte feature with 'w' set\n");
200*f603807bSTomohiro Kusumi 		return EINVAL;
201*f603807bSTomohiro Kusumi 	}
202*f603807bSTomohiro Kusumi 
203*f603807bSTomohiro Kusumi 	return 0;
204*f603807bSTomohiro Kusumi }
205*f603807bSTomohiro Kusumi 
206*f603807bSTomohiro Kusumi static int
207*f603807bSTomohiro Kusumi dm_target_flakey_destroy(dm_table_entry_t *table_en)
208*f603807bSTomohiro Kusumi {
209*f603807bSTomohiro Kusumi 	dm_target_flakey_config_t *tfc;
210*f603807bSTomohiro Kusumi 
211*f603807bSTomohiro Kusumi 	tfc = table_en->target_config;
212*f603807bSTomohiro Kusumi 	if (tfc == NULL)
213*f603807bSTomohiro Kusumi 		return 0;
214*f603807bSTomohiro Kusumi 
215*f603807bSTomohiro Kusumi 	dm_pdev_decr(tfc->pdev);
216*f603807bSTomohiro Kusumi 
217*f603807bSTomohiro Kusumi 	kfree(tfc, M_DMFLAKEY);
218*f603807bSTomohiro Kusumi 
219*f603807bSTomohiro Kusumi 	return 0;
220*f603807bSTomohiro Kusumi }
221*f603807bSTomohiro Kusumi 
222*f603807bSTomohiro Kusumi static int
223*f603807bSTomohiro Kusumi dm_target_flakey_strategy(dm_table_entry_t *table_en, struct buf *bp)
224*f603807bSTomohiro Kusumi {
225*f603807bSTomohiro Kusumi 	dm_target_flakey_config_t *tfc;
226*f603807bSTomohiro Kusumi 	int elapsed;
227*f603807bSTomohiro Kusumi 
228*f603807bSTomohiro Kusumi 	tfc = table_en->target_config;
229*f603807bSTomohiro Kusumi 
230*f603807bSTomohiro Kusumi 	elapsed = (ticks - tfc->offset_time) / hz;
231*f603807bSTomohiro Kusumi 	if (elapsed % (tfc->up_int + tfc->down_int) >= tfc->up_int) {
232*f603807bSTomohiro Kusumi 		switch (bp->b_cmd) {
233*f603807bSTomohiro Kusumi 		case BUF_CMD_READ:
234*f603807bSTomohiro Kusumi 			return _flakey_read(tfc, bp);
235*f603807bSTomohiro Kusumi 		case BUF_CMD_WRITE:
236*f603807bSTomohiro Kusumi 			return _flakey_write(tfc, bp);
237*f603807bSTomohiro Kusumi 		default:
238*f603807bSTomohiro Kusumi 			break;
239*f603807bSTomohiro Kusumi 		}
240*f603807bSTomohiro Kusumi 	}
241*f603807bSTomohiro Kusumi 
242*f603807bSTomohiro Kusumi 	/* This is what linear target does */
243*f603807bSTomohiro Kusumi 	_submit(tfc, &bp->b_bio1);
244*f603807bSTomohiro Kusumi 
245*f603807bSTomohiro Kusumi 	return 0;
246*f603807bSTomohiro Kusumi }
247*f603807bSTomohiro Kusumi 
248*f603807bSTomohiro Kusumi static __inline
249*f603807bSTomohiro Kusumi void
250*f603807bSTomohiro Kusumi _submit(dm_target_flakey_config_t *tfc, struct bio *bio)
251*f603807bSTomohiro Kusumi {
252*f603807bSTomohiro Kusumi 	bio->bio_offset += tfc->offset * DEV_BSIZE;
253*f603807bSTomohiro Kusumi 	vn_strategy(tfc->pdev->pdev_vnode, bio);
254*f603807bSTomohiro Kusumi }
255*f603807bSTomohiro Kusumi 
256*f603807bSTomohiro Kusumi static __inline
257*f603807bSTomohiro Kusumi void
258*f603807bSTomohiro Kusumi _flakey_eio_buf(struct buf *bp)
259*f603807bSTomohiro Kusumi {
260*f603807bSTomohiro Kusumi 	bp->b_error = EIO;
261*f603807bSTomohiro Kusumi 	bp->b_resid = 0;
262*f603807bSTomohiro Kusumi }
263*f603807bSTomohiro Kusumi 
264*f603807bSTomohiro Kusumi static void
265*f603807bSTomohiro Kusumi _flakey_read_iodone(struct bio *bio)
266*f603807bSTomohiro Kusumi {
267*f603807bSTomohiro Kusumi 	struct bio *obio;
268*f603807bSTomohiro Kusumi 	dm_target_flakey_config_t *tfc;
269*f603807bSTomohiro Kusumi 
270*f603807bSTomohiro Kusumi 	tfc = bio->bio_caller_info1.ptr;
271*f603807bSTomohiro Kusumi 	obio = pop_bio(bio);
272*f603807bSTomohiro Kusumi 
273*f603807bSTomohiro Kusumi 	/*
274*f603807bSTomohiro Kusumi 	 * Linux dm-flakey has changed its read behavior in 2016.
275*f603807bSTomohiro Kusumi 	 * This conditional is to sync with that change.
276*f603807bSTomohiro Kusumi 	 */
277*f603807bSTomohiro Kusumi 	if (tfc->corrupt_buf_byte && tfc->corrupt_buf_rw == BUF_CMD_READ)
278*f603807bSTomohiro Kusumi 		_flakey_corrupt_buf(tfc, obio);
279*f603807bSTomohiro Kusumi 	else if (!tfc->drop_writes)
280*f603807bSTomohiro Kusumi 		_flakey_eio_buf(bio->bio_buf);
281*f603807bSTomohiro Kusumi 
282*f603807bSTomohiro Kusumi 	biodone(obio);
283*f603807bSTomohiro Kusumi }
284*f603807bSTomohiro Kusumi 
285*f603807bSTomohiro Kusumi static int
286*f603807bSTomohiro Kusumi _flakey_read(dm_target_flakey_config_t *tfc, struct buf *bp)
287*f603807bSTomohiro Kusumi {
288*f603807bSTomohiro Kusumi 	struct bio *bio = &bp->b_bio1;
289*f603807bSTomohiro Kusumi 	struct bio *nbio;
290*f603807bSTomohiro Kusumi 
291*f603807bSTomohiro Kusumi 	/*
292*f603807bSTomohiro Kusumi 	 * Linux dm-flakey has changed its read behavior in 2016.
293*f603807bSTomohiro Kusumi 	 * This conditional is to sync with that change.
294*f603807bSTomohiro Kusumi 	 */
295*f603807bSTomohiro Kusumi 	if (!tfc->corrupt_buf_byte && !tfc->drop_writes) {
296*f603807bSTomohiro Kusumi 		_flakey_eio_buf(bp);
297*f603807bSTomohiro Kusumi 		biodone(bio);
298*f603807bSTomohiro Kusumi 		return 0;
299*f603807bSTomohiro Kusumi 	}
300*f603807bSTomohiro Kusumi 
301*f603807bSTomohiro Kusumi 	nbio = push_bio(bio);
302*f603807bSTomohiro Kusumi 	nbio->bio_done = _flakey_read_iodone;
303*f603807bSTomohiro Kusumi 	nbio->bio_caller_info1.ptr = tfc;
304*f603807bSTomohiro Kusumi 	nbio->bio_offset = pop_bio(nbio)->bio_offset;
305*f603807bSTomohiro Kusumi 
306*f603807bSTomohiro Kusumi 	_submit(tfc, nbio);
307*f603807bSTomohiro Kusumi 
308*f603807bSTomohiro Kusumi 	return 0;
309*f603807bSTomohiro Kusumi }
310*f603807bSTomohiro Kusumi 
311*f603807bSTomohiro Kusumi static int
312*f603807bSTomohiro Kusumi _flakey_write(dm_target_flakey_config_t *tfc, struct buf *bp)
313*f603807bSTomohiro Kusumi {
314*f603807bSTomohiro Kusumi 	struct bio *bio = &bp->b_bio1;
315*f603807bSTomohiro Kusumi 
316*f603807bSTomohiro Kusumi 	if (tfc->drop_writes) {
317*f603807bSTomohiro Kusumi 		dmdebug("bio=%p drop_writes offset=%ju\n",
318*f603807bSTomohiro Kusumi 			bio, bio->bio_offset);
319*f603807bSTomohiro Kusumi 		biodone(bio);
320*f603807bSTomohiro Kusumi 		return 0;
321*f603807bSTomohiro Kusumi 	}
322*f603807bSTomohiro Kusumi 
323*f603807bSTomohiro Kusumi 	if (tfc->corrupt_buf_byte && tfc->corrupt_buf_rw == BUF_CMD_WRITE) {
324*f603807bSTomohiro Kusumi 		_flakey_corrupt_buf(tfc, bio);
325*f603807bSTomohiro Kusumi 		_submit(tfc, bio);
326*f603807bSTomohiro Kusumi 		return 0;
327*f603807bSTomohiro Kusumi 	}
328*f603807bSTomohiro Kusumi 
329*f603807bSTomohiro Kusumi 	/* Error all I/Os if neither of the above two */
330*f603807bSTomohiro Kusumi 	_flakey_eio_buf(bp);
331*f603807bSTomohiro Kusumi 	biodone(bio);
332*f603807bSTomohiro Kusumi 
333*f603807bSTomohiro Kusumi 	return 0;
334*f603807bSTomohiro Kusumi }
335*f603807bSTomohiro Kusumi 
336*f603807bSTomohiro Kusumi static int
337*f603807bSTomohiro Kusumi _flakey_corrupt_buf(dm_target_flakey_config_t *tfc, struct bio *bio)
338*f603807bSTomohiro Kusumi {
339*f603807bSTomohiro Kusumi 	struct buf *bp;
340*f603807bSTomohiro Kusumi 
341*f603807bSTomohiro Kusumi 	bp = bio->bio_buf;
342*f603807bSTomohiro Kusumi 
343*f603807bSTomohiro Kusumi 	if (bp->b_data == NULL)
344*f603807bSTomohiro Kusumi 		return 1;
345*f603807bSTomohiro Kusumi 	if (bp->b_error)
346*f603807bSTomohiro Kusumi 		return 1;  /* Don't corrupt on error */
347*f603807bSTomohiro Kusumi 	if (bp->b_bcount < tfc->corrupt_buf_byte)
348*f603807bSTomohiro Kusumi 		return 1;
349*f603807bSTomohiro Kusumi 	if ((bp->b_flags & tfc->corrupt_buf_flags) != tfc->corrupt_buf_flags)
350*f603807bSTomohiro Kusumi 		return 1;
351*f603807bSTomohiro Kusumi 
352*f603807bSTomohiro Kusumi 	bp->b_data[tfc->corrupt_buf_byte - 1] = tfc->corrupt_buf_value;
353*f603807bSTomohiro Kusumi 	dmdebug("bio=%p dir=%c offset=%ju Nth=%u value=%u\n",
354*f603807bSTomohiro Kusumi 		bio,
355*f603807bSTomohiro Kusumi 		FLAKEY_CORRUPT_DIR(tfc),
356*f603807bSTomohiro Kusumi 		bio->bio_offset,
357*f603807bSTomohiro Kusumi 		tfc->corrupt_buf_byte,
358*f603807bSTomohiro Kusumi 		tfc->corrupt_buf_value);
359*f603807bSTomohiro Kusumi 
360*f603807bSTomohiro Kusumi 	return 0;
361*f603807bSTomohiro Kusumi }
362*f603807bSTomohiro Kusumi 
363*f603807bSTomohiro Kusumi static char *
364*f603807bSTomohiro Kusumi dm_target_flakey_table(void *target_config)
365*f603807bSTomohiro Kusumi {
366*f603807bSTomohiro Kusumi 	dm_target_flakey_config_t *tfc;
367*f603807bSTomohiro Kusumi 	char *params, *p;
368*f603807bSTomohiro Kusumi 	int drop_writes;
369*f603807bSTomohiro Kusumi 
370*f603807bSTomohiro Kusumi 	tfc = target_config;
371*f603807bSTomohiro Kusumi 	KKASSERT(tfc != NULL);
372*f603807bSTomohiro Kusumi 
373*f603807bSTomohiro Kusumi 	drop_writes = tfc->drop_writes;
374*f603807bSTomohiro Kusumi 
375*f603807bSTomohiro Kusumi 	params = dm_alloc_string(DM_MAX_PARAMS_SIZE);
376*f603807bSTomohiro Kusumi 	p = params;
377*f603807bSTomohiro Kusumi 	p += ksnprintf(p, DM_MAX_PARAMS_SIZE, "%s %d %d %d %u ",
378*f603807bSTomohiro Kusumi 		tfc->pdev->udev_name, tfc->offset_time,
379*f603807bSTomohiro Kusumi 		tfc->up_int, tfc->down_int,
380*f603807bSTomohiro Kusumi 		drop_writes + (tfc->corrupt_buf_byte > 0) * 5);
381*f603807bSTomohiro Kusumi 
382*f603807bSTomohiro Kusumi 	if (drop_writes)
383*f603807bSTomohiro Kusumi 		p += ksnprintf(p, DM_MAX_PARAMS_SIZE, "drop_writes ");
384*f603807bSTomohiro Kusumi 
385*f603807bSTomohiro Kusumi 	if (tfc->corrupt_buf_byte)
386*f603807bSTomohiro Kusumi 		p += ksnprintf(p, DM_MAX_PARAMS_SIZE,
387*f603807bSTomohiro Kusumi 			"corrupt_bio_byte %u %c %u %u ",
388*f603807bSTomohiro Kusumi 			tfc->corrupt_buf_byte,
389*f603807bSTomohiro Kusumi 			FLAKEY_CORRUPT_DIR(tfc),
390*f603807bSTomohiro Kusumi 			tfc->corrupt_buf_value,
391*f603807bSTomohiro Kusumi 			tfc->corrupt_buf_flags);
392*f603807bSTomohiro Kusumi 	*(--p) = '\0';
393*f603807bSTomohiro Kusumi 
394*f603807bSTomohiro Kusumi 	return params;
395*f603807bSTomohiro Kusumi }
396*f603807bSTomohiro Kusumi 
397*f603807bSTomohiro Kusumi static int
398*f603807bSTomohiro Kusumi dmtf_mod_handler(module_t mod, int type, void *unused)
399*f603807bSTomohiro Kusumi {
400*f603807bSTomohiro Kusumi 	dm_target_t *dmt = NULL;
401*f603807bSTomohiro Kusumi 	int err = 0;
402*f603807bSTomohiro Kusumi 
403*f603807bSTomohiro Kusumi 	switch(type) {
404*f603807bSTomohiro Kusumi 	case MOD_LOAD:
405*f603807bSTomohiro Kusumi 		if ((dmt = dm_target_lookup("flakey")) != NULL) {
406*f603807bSTomohiro Kusumi 			dm_target_unbusy(dmt);
407*f603807bSTomohiro Kusumi 			return EEXIST;
408*f603807bSTomohiro Kusumi 		}
409*f603807bSTomohiro Kusumi 		dmt = dm_target_alloc("flakey");
410*f603807bSTomohiro Kusumi 		dmt->version[0] = 1;
411*f603807bSTomohiro Kusumi 		dmt->version[1] = 0;
412*f603807bSTomohiro Kusumi 		dmt->version[2] = 0;
413*f603807bSTomohiro Kusumi 		strlcpy(dmt->name, "flakey", DM_MAX_TYPE_NAME);
414*f603807bSTomohiro Kusumi 		dmt->init = &dm_target_flakey_init;
415*f603807bSTomohiro Kusumi 		dmt->destroy = &dm_target_flakey_destroy;
416*f603807bSTomohiro Kusumi 		dmt->strategy = &dm_target_flakey_strategy;
417*f603807bSTomohiro Kusumi 		dmt->table = &dm_target_flakey_table;
418*f603807bSTomohiro Kusumi 
419*f603807bSTomohiro Kusumi 		err = dm_target_insert(dmt);
420*f603807bSTomohiro Kusumi 		if (err == 0)
421*f603807bSTomohiro Kusumi 			kprintf("dm_target_flakey: Successfully initialized\n");
422*f603807bSTomohiro Kusumi 		break;
423*f603807bSTomohiro Kusumi 
424*f603807bSTomohiro Kusumi 	case MOD_UNLOAD:
425*f603807bSTomohiro Kusumi 		err = dm_target_remove("flakey");
426*f603807bSTomohiro Kusumi 		if (err == 0)
427*f603807bSTomohiro Kusumi 			kprintf("dm_target_flakey: unloaded\n");
428*f603807bSTomohiro Kusumi 		break;
429*f603807bSTomohiro Kusumi 	}
430*f603807bSTomohiro Kusumi 
431*f603807bSTomohiro Kusumi 	return err;
432*f603807bSTomohiro Kusumi }
433*f603807bSTomohiro Kusumi 
434*f603807bSTomohiro Kusumi DM_TARGET_MODULE(dm_target_flakey, dmtf_mod_handler);
435