13407ef52SJosef Bacik /* 23407ef52SJosef Bacik * Copyright (C) 2003 Sistina Software (UK) Limited. 33407ef52SJosef Bacik * Copyright (C) 2004, 2010 Red Hat, Inc. All rights reserved. 43407ef52SJosef Bacik * 53407ef52SJosef Bacik * This file is released under the GPL. 63407ef52SJosef Bacik */ 73407ef52SJosef Bacik 83407ef52SJosef Bacik #include <linux/device-mapper.h> 93407ef52SJosef Bacik 103407ef52SJosef Bacik #include <linux/module.h> 113407ef52SJosef Bacik #include <linux/init.h> 123407ef52SJosef Bacik #include <linux/blkdev.h> 133407ef52SJosef Bacik #include <linux/bio.h> 143407ef52SJosef Bacik #include <linux/slab.h> 153407ef52SJosef Bacik 163407ef52SJosef Bacik #define DM_MSG_PREFIX "flakey" 173407ef52SJosef Bacik 183407ef52SJosef Bacik /* 193407ef52SJosef Bacik * Flakey: Used for testing only, simulates intermittent, 203407ef52SJosef Bacik * catastrophic device failure. 213407ef52SJosef Bacik */ 223407ef52SJosef Bacik struct flakey_c { 233407ef52SJosef Bacik struct dm_dev *dev; 243407ef52SJosef Bacik unsigned long start_time; 253407ef52SJosef Bacik sector_t start; 263407ef52SJosef Bacik unsigned up_interval; 273407ef52SJosef Bacik unsigned down_interval; 28*b26f5e3dSMike Snitzer unsigned long flags; 293407ef52SJosef Bacik }; 303407ef52SJosef Bacik 31*b26f5e3dSMike Snitzer enum feature_flag_bits { 32*b26f5e3dSMike Snitzer DROP_WRITES 33*b26f5e3dSMike Snitzer }; 34*b26f5e3dSMike Snitzer 35*b26f5e3dSMike Snitzer static int parse_features(struct dm_arg_set *as, struct flakey_c *fc, 36*b26f5e3dSMike Snitzer struct dm_target *ti) 37dfd068b0SMike Snitzer { 38dfd068b0SMike Snitzer int r; 39dfd068b0SMike Snitzer unsigned argc; 40dfd068b0SMike Snitzer const char *arg_name; 41dfd068b0SMike Snitzer 42dfd068b0SMike Snitzer static struct dm_arg _args[] = { 43*b26f5e3dSMike Snitzer {0, 1, "Invalid number of feature args"}, 44dfd068b0SMike Snitzer }; 45dfd068b0SMike Snitzer 46dfd068b0SMike Snitzer /* No feature arguments supplied. */ 47dfd068b0SMike Snitzer if (!as->argc) 48dfd068b0SMike Snitzer return 0; 49dfd068b0SMike Snitzer 50dfd068b0SMike Snitzer r = dm_read_arg_group(_args, as, &argc, &ti->error); 51dfd068b0SMike Snitzer if (r) 52dfd068b0SMike Snitzer return -EINVAL; 53dfd068b0SMike Snitzer 54dfd068b0SMike Snitzer while (argc && !r) { 55dfd068b0SMike Snitzer arg_name = dm_shift_arg(as); 56dfd068b0SMike Snitzer argc--; 57dfd068b0SMike Snitzer 58*b26f5e3dSMike Snitzer /* 59*b26f5e3dSMike Snitzer * drop_writes 60*b26f5e3dSMike Snitzer */ 61*b26f5e3dSMike Snitzer if (!strcasecmp(arg_name, "drop_writes")) { 62*b26f5e3dSMike Snitzer if (test_and_set_bit(DROP_WRITES, &fc->flags)) { 63*b26f5e3dSMike Snitzer ti->error = "Feature drop_writes duplicated"; 64*b26f5e3dSMike Snitzer return -EINVAL; 65*b26f5e3dSMike Snitzer } 66*b26f5e3dSMike Snitzer 67*b26f5e3dSMike Snitzer continue; 68*b26f5e3dSMike Snitzer } 69*b26f5e3dSMike Snitzer 70dfd068b0SMike Snitzer ti->error = "Unrecognised flakey feature requested"; 71dfd068b0SMike Snitzer r = -EINVAL; 72dfd068b0SMike Snitzer } 73dfd068b0SMike Snitzer 74dfd068b0SMike Snitzer return r; 75dfd068b0SMike Snitzer } 76dfd068b0SMike Snitzer 773407ef52SJosef Bacik /* 78dfd068b0SMike Snitzer * Construct a flakey mapping: 79dfd068b0SMike Snitzer * <dev_path> <offset> <up interval> <down interval> [<#feature args> [<arg>]*] 80*b26f5e3dSMike Snitzer * 81*b26f5e3dSMike Snitzer * Feature args: 82*b26f5e3dSMike Snitzer * [drop_writes] 833407ef52SJosef Bacik */ 843407ef52SJosef Bacik static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv) 853407ef52SJosef Bacik { 86dfd068b0SMike Snitzer static struct dm_arg _args[] = { 87dfd068b0SMike Snitzer {0, UINT_MAX, "Invalid up interval"}, 88dfd068b0SMike Snitzer {0, UINT_MAX, "Invalid down interval"}, 89dfd068b0SMike Snitzer }; 903407ef52SJosef Bacik 91dfd068b0SMike Snitzer int r; 92dfd068b0SMike Snitzer struct flakey_c *fc; 93dfd068b0SMike Snitzer unsigned long long tmpll; 94dfd068b0SMike Snitzer struct dm_arg_set as; 95dfd068b0SMike Snitzer const char *devname; 96dfd068b0SMike Snitzer 97dfd068b0SMike Snitzer as.argc = argc; 98dfd068b0SMike Snitzer as.argv = argv; 99dfd068b0SMike Snitzer 100dfd068b0SMike Snitzer if (argc < 4) { 101dfd068b0SMike Snitzer ti->error = "Invalid argument count"; 1023407ef52SJosef Bacik return -EINVAL; 1033407ef52SJosef Bacik } 1043407ef52SJosef Bacik 105*b26f5e3dSMike Snitzer fc = kzalloc(sizeof(*fc), GFP_KERNEL); 1063407ef52SJosef Bacik if (!fc) { 107dfd068b0SMike Snitzer ti->error = "Cannot allocate linear context"; 1083407ef52SJosef Bacik return -ENOMEM; 1093407ef52SJosef Bacik } 1103407ef52SJosef Bacik fc->start_time = jiffies; 1113407ef52SJosef Bacik 112dfd068b0SMike Snitzer devname = dm_shift_arg(&as); 1133407ef52SJosef Bacik 114dfd068b0SMike Snitzer if (sscanf(dm_shift_arg(&as), "%llu", &tmpll) != 1) { 115dfd068b0SMike Snitzer ti->error = "Invalid device sector"; 1163407ef52SJosef Bacik goto bad; 1173407ef52SJosef Bacik } 118dfd068b0SMike Snitzer fc->start = tmpll; 1193407ef52SJosef Bacik 120dfd068b0SMike Snitzer r = dm_read_arg(_args, &as, &fc->up_interval, &ti->error); 121dfd068b0SMike Snitzer if (r) 1223407ef52SJosef Bacik goto bad; 123dfd068b0SMike Snitzer 124dfd068b0SMike Snitzer r = dm_read_arg(_args, &as, &fc->down_interval, &ti->error); 125dfd068b0SMike Snitzer if (r) 126dfd068b0SMike Snitzer goto bad; 1273407ef52SJosef Bacik 1283407ef52SJosef Bacik if (!(fc->up_interval + fc->down_interval)) { 129dfd068b0SMike Snitzer ti->error = "Total (up + down) interval is zero"; 1303407ef52SJosef Bacik goto bad; 1313407ef52SJosef Bacik } 1323407ef52SJosef Bacik 1333407ef52SJosef Bacik if (fc->up_interval + fc->down_interval < fc->up_interval) { 134dfd068b0SMike Snitzer ti->error = "Interval overflow"; 1353407ef52SJosef Bacik goto bad; 1363407ef52SJosef Bacik } 1373407ef52SJosef Bacik 138*b26f5e3dSMike Snitzer r = parse_features(&as, fc, ti); 139dfd068b0SMike Snitzer if (r) 140dfd068b0SMike Snitzer goto bad; 141dfd068b0SMike Snitzer 142dfd068b0SMike Snitzer if (dm_get_device(ti, devname, dm_table_get_mode(ti->table), &fc->dev)) { 143dfd068b0SMike Snitzer ti->error = "Device lookup failed"; 1443407ef52SJosef Bacik goto bad; 1453407ef52SJosef Bacik } 1463407ef52SJosef Bacik 1473407ef52SJosef Bacik ti->num_flush_requests = 1; 14830e4171bSMike Snitzer ti->num_discard_requests = 1; 1493407ef52SJosef Bacik ti->private = fc; 1503407ef52SJosef Bacik return 0; 1513407ef52SJosef Bacik 1523407ef52SJosef Bacik bad: 1533407ef52SJosef Bacik kfree(fc); 1543407ef52SJosef Bacik return -EINVAL; 1553407ef52SJosef Bacik } 1563407ef52SJosef Bacik 1573407ef52SJosef Bacik static void flakey_dtr(struct dm_target *ti) 1583407ef52SJosef Bacik { 1593407ef52SJosef Bacik struct flakey_c *fc = ti->private; 1603407ef52SJosef Bacik 1613407ef52SJosef Bacik dm_put_device(ti, fc->dev); 1623407ef52SJosef Bacik kfree(fc); 1633407ef52SJosef Bacik } 1643407ef52SJosef Bacik 1653407ef52SJosef Bacik static sector_t flakey_map_sector(struct dm_target *ti, sector_t bi_sector) 1663407ef52SJosef Bacik { 1673407ef52SJosef Bacik struct flakey_c *fc = ti->private; 1683407ef52SJosef Bacik 16930e4171bSMike Snitzer return fc->start + dm_target_offset(ti, bi_sector); 1703407ef52SJosef Bacik } 1713407ef52SJosef Bacik 1723407ef52SJosef Bacik static void flakey_map_bio(struct dm_target *ti, struct bio *bio) 1733407ef52SJosef Bacik { 1743407ef52SJosef Bacik struct flakey_c *fc = ti->private; 1753407ef52SJosef Bacik 1763407ef52SJosef Bacik bio->bi_bdev = fc->dev->bdev; 1773407ef52SJosef Bacik if (bio_sectors(bio)) 1783407ef52SJosef Bacik bio->bi_sector = flakey_map_sector(ti, bio->bi_sector); 1793407ef52SJosef Bacik } 1803407ef52SJosef Bacik 1813407ef52SJosef Bacik static int flakey_map(struct dm_target *ti, struct bio *bio, 1823407ef52SJosef Bacik union map_info *map_context) 1833407ef52SJosef Bacik { 1843407ef52SJosef Bacik struct flakey_c *fc = ti->private; 1853407ef52SJosef Bacik unsigned elapsed; 186*b26f5e3dSMike Snitzer unsigned rw; 1873407ef52SJosef Bacik 1883407ef52SJosef Bacik /* Are we alive ? */ 1893407ef52SJosef Bacik elapsed = (jiffies - fc->start_time) / HZ; 190*b26f5e3dSMike Snitzer if (elapsed % (fc->up_interval + fc->down_interval) >= fc->up_interval) { 191*b26f5e3dSMike Snitzer rw = bio_data_dir(bio); 1923407ef52SJosef Bacik 193*b26f5e3dSMike Snitzer /* 194*b26f5e3dSMike Snitzer * Drop writes. Map reads as normal. 195*b26f5e3dSMike Snitzer */ 196*b26f5e3dSMike Snitzer if (test_bit(DROP_WRITES, &fc->flags)) { 197*b26f5e3dSMike Snitzer if (rw == WRITE) { 198*b26f5e3dSMike Snitzer bio_endio(bio, 0); 199*b26f5e3dSMike Snitzer return DM_MAPIO_SUBMITTED; 200*b26f5e3dSMike Snitzer } 201*b26f5e3dSMike Snitzer goto map_bio; 202*b26f5e3dSMike Snitzer } 203*b26f5e3dSMike Snitzer 204*b26f5e3dSMike Snitzer /* 205*b26f5e3dSMike Snitzer * Default setting errors all I/O. 206*b26f5e3dSMike Snitzer */ 207*b26f5e3dSMike Snitzer return -EIO; 208*b26f5e3dSMike Snitzer } 209*b26f5e3dSMike Snitzer 210*b26f5e3dSMike Snitzer map_bio: 2113407ef52SJosef Bacik flakey_map_bio(ti, bio); 2123407ef52SJosef Bacik 2133407ef52SJosef Bacik return DM_MAPIO_REMAPPED; 2143407ef52SJosef Bacik } 2153407ef52SJosef Bacik 2163407ef52SJosef Bacik static int flakey_status(struct dm_target *ti, status_type_t type, 2173407ef52SJosef Bacik char *result, unsigned int maxlen) 2183407ef52SJosef Bacik { 219*b26f5e3dSMike Snitzer unsigned sz = 0; 2203407ef52SJosef Bacik struct flakey_c *fc = ti->private; 221*b26f5e3dSMike Snitzer unsigned drop_writes; 2223407ef52SJosef Bacik 2233407ef52SJosef Bacik switch (type) { 2243407ef52SJosef Bacik case STATUSTYPE_INFO: 2253407ef52SJosef Bacik result[0] = '\0'; 2263407ef52SJosef Bacik break; 2273407ef52SJosef Bacik 2283407ef52SJosef Bacik case STATUSTYPE_TABLE: 229*b26f5e3dSMike Snitzer DMEMIT("%s %llu %u %u ", fc->dev->name, 2303407ef52SJosef Bacik (unsigned long long)fc->start, fc->up_interval, 2313407ef52SJosef Bacik fc->down_interval); 232*b26f5e3dSMike Snitzer 233*b26f5e3dSMike Snitzer drop_writes = test_bit(DROP_WRITES, &fc->flags); 234*b26f5e3dSMike Snitzer DMEMIT("%u ", drop_writes); 235*b26f5e3dSMike Snitzer if (drop_writes) 236*b26f5e3dSMike Snitzer DMEMIT("drop_writes "); 2373407ef52SJosef Bacik break; 2383407ef52SJosef Bacik } 2393407ef52SJosef Bacik return 0; 2403407ef52SJosef Bacik } 2413407ef52SJosef Bacik 2423407ef52SJosef Bacik static int flakey_ioctl(struct dm_target *ti, unsigned int cmd, unsigned long arg) 2433407ef52SJosef Bacik { 2443407ef52SJosef Bacik struct flakey_c *fc = ti->private; 2453407ef52SJosef Bacik 2463407ef52SJosef Bacik return __blkdev_driver_ioctl(fc->dev->bdev, fc->dev->mode, cmd, arg); 2473407ef52SJosef Bacik } 2483407ef52SJosef Bacik 2493407ef52SJosef Bacik static int flakey_merge(struct dm_target *ti, struct bvec_merge_data *bvm, 2503407ef52SJosef Bacik struct bio_vec *biovec, int max_size) 2513407ef52SJosef Bacik { 2523407ef52SJosef Bacik struct flakey_c *fc = ti->private; 2533407ef52SJosef Bacik struct request_queue *q = bdev_get_queue(fc->dev->bdev); 2543407ef52SJosef Bacik 2553407ef52SJosef Bacik if (!q->merge_bvec_fn) 2563407ef52SJosef Bacik return max_size; 2573407ef52SJosef Bacik 2583407ef52SJosef Bacik bvm->bi_bdev = fc->dev->bdev; 2593407ef52SJosef Bacik bvm->bi_sector = flakey_map_sector(ti, bvm->bi_sector); 2603407ef52SJosef Bacik 2613407ef52SJosef Bacik return min(max_size, q->merge_bvec_fn(q, bvm, biovec)); 2623407ef52SJosef Bacik } 2633407ef52SJosef Bacik 2643407ef52SJosef Bacik static int flakey_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn, void *data) 2653407ef52SJosef Bacik { 2663407ef52SJosef Bacik struct flakey_c *fc = ti->private; 2673407ef52SJosef Bacik 2683407ef52SJosef Bacik return fn(ti, fc->dev, fc->start, ti->len, data); 2693407ef52SJosef Bacik } 2703407ef52SJosef Bacik 2713407ef52SJosef Bacik static struct target_type flakey_target = { 2723407ef52SJosef Bacik .name = "flakey", 273dfd068b0SMike Snitzer .version = {1, 2, 0}, 2743407ef52SJosef Bacik .module = THIS_MODULE, 2753407ef52SJosef Bacik .ctr = flakey_ctr, 2763407ef52SJosef Bacik .dtr = flakey_dtr, 2773407ef52SJosef Bacik .map = flakey_map, 2783407ef52SJosef Bacik .status = flakey_status, 2793407ef52SJosef Bacik .ioctl = flakey_ioctl, 2803407ef52SJosef Bacik .merge = flakey_merge, 2813407ef52SJosef Bacik .iterate_devices = flakey_iterate_devices, 2823407ef52SJosef Bacik }; 2833407ef52SJosef Bacik 2843407ef52SJosef Bacik static int __init dm_flakey_init(void) 2853407ef52SJosef Bacik { 2863407ef52SJosef Bacik int r = dm_register_target(&flakey_target); 2873407ef52SJosef Bacik 2883407ef52SJosef Bacik if (r < 0) 2893407ef52SJosef Bacik DMERR("register failed %d", r); 2903407ef52SJosef Bacik 2913407ef52SJosef Bacik return r; 2923407ef52SJosef Bacik } 2933407ef52SJosef Bacik 2943407ef52SJosef Bacik static void __exit dm_flakey_exit(void) 2953407ef52SJosef Bacik { 2963407ef52SJosef Bacik dm_unregister_target(&flakey_target); 2973407ef52SJosef Bacik } 2983407ef52SJosef Bacik 2993407ef52SJosef Bacik /* Module hooks */ 3003407ef52SJosef Bacik module_init(dm_flakey_init); 3013407ef52SJosef Bacik module_exit(dm_flakey_exit); 3023407ef52SJosef Bacik 3033407ef52SJosef Bacik MODULE_DESCRIPTION(DM_NAME " flakey target"); 3043407ef52SJosef Bacik MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>"); 3053407ef52SJosef Bacik MODULE_LICENSE("GPL"); 306