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