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