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