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