11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Copyright (C) 2001-2003 Sistina Software (UK) Limited. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * This file is released under the GPL. 51da177e4SLinus Torvalds */ 61da177e4SLinus Torvalds 7586e80e6SMikulas Patocka #include <linux/device-mapper.h> 81da177e4SLinus Torvalds 91da177e4SLinus Torvalds #include <linux/module.h> 101da177e4SLinus Torvalds #include <linux/init.h> 111da177e4SLinus Torvalds #include <linux/blkdev.h> 121da177e4SLinus Torvalds #include <linux/bio.h> 131da177e4SLinus Torvalds #include <linux/slab.h> 146f3c3f0aSvignesh babu #include <linux/log2.h> 151da177e4SLinus Torvalds 1672d94861SAlasdair G Kergon #define DM_MSG_PREFIX "striped" 17a25eb944SBrian Wood #define DM_IO_ERROR_THRESHOLD 15 1872d94861SAlasdair G Kergon 191da177e4SLinus Torvalds struct stripe { 201da177e4SLinus Torvalds struct dm_dev *dev; 211da177e4SLinus Torvalds sector_t physical_start; 22a25eb944SBrian Wood 23a25eb944SBrian Wood atomic_t error_count; 241da177e4SLinus Torvalds }; 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds struct stripe_c { 271da177e4SLinus Torvalds uint32_t stripes; 28c96053b7SMikulas Patocka int stripes_shift; 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds /* The size of this target / num. stripes */ 311da177e4SLinus Torvalds sector_t stripe_width; 321da177e4SLinus Torvalds 33eb850de6SMike Snitzer uint32_t chunk_size; 3433d07c0dSMikulas Patocka int chunk_size_shift; 351da177e4SLinus Torvalds 36a25eb944SBrian Wood /* Needed for handling events */ 37a25eb944SBrian Wood struct dm_target *ti; 38a25eb944SBrian Wood 39a25eb944SBrian Wood /* Work struct used for triggering events*/ 40f521f074STejun Heo struct work_struct trigger_event; 41a25eb944SBrian Wood 421da177e4SLinus Torvalds struct stripe stripe[0]; 431da177e4SLinus Torvalds }; 441da177e4SLinus Torvalds 45a25eb944SBrian Wood /* 46a25eb944SBrian Wood * An event is triggered whenever a drive 47a25eb944SBrian Wood * drops out of a stripe volume. 48a25eb944SBrian Wood */ 49a25eb944SBrian Wood static void trigger_event(struct work_struct *work) 50a25eb944SBrian Wood { 51f521f074STejun Heo struct stripe_c *sc = container_of(work, struct stripe_c, 52f521f074STejun Heo trigger_event); 53a25eb944SBrian Wood dm_table_event(sc->ti->table); 54a25eb944SBrian Wood } 55a25eb944SBrian Wood 561da177e4SLinus Torvalds static inline struct stripe_c *alloc_context(unsigned int stripes) 571da177e4SLinus Torvalds { 581da177e4SLinus Torvalds size_t len; 591da177e4SLinus Torvalds 60d63a5ce3SMikulas Patocka if (dm_array_too_big(sizeof(struct stripe_c), sizeof(struct stripe), 611da177e4SLinus Torvalds stripes)) 621da177e4SLinus Torvalds return NULL; 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds len = sizeof(struct stripe_c) + (sizeof(struct stripe) * stripes); 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds return kmalloc(len, GFP_KERNEL); 671da177e4SLinus Torvalds } 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds /* 701da177e4SLinus Torvalds * Parse a single <dev> <sector> pair 711da177e4SLinus Torvalds */ 721da177e4SLinus Torvalds static int get_stripe(struct dm_target *ti, struct stripe_c *sc, 731da177e4SLinus Torvalds unsigned int stripe, char **argv) 741da177e4SLinus Torvalds { 754ee218cdSAndrew Morton unsigned long long start; 7631998ef1SMikulas Patocka char dummy; 771da177e4SLinus Torvalds 7831998ef1SMikulas Patocka if (sscanf(argv[1], "%llu%c", &start, &dummy) != 1) 791da177e4SLinus Torvalds return -EINVAL; 801da177e4SLinus Torvalds 818215d6ecSNikanth Karthikesan if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), 821da177e4SLinus Torvalds &sc->stripe[stripe].dev)) 831da177e4SLinus Torvalds return -ENXIO; 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds sc->stripe[stripe].physical_start = start; 86a25eb944SBrian Wood 871da177e4SLinus Torvalds return 0; 881da177e4SLinus Torvalds } 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds /* 911da177e4SLinus Torvalds * Construct a striped mapping. 92eb850de6SMike Snitzer * <number of stripes> <chunk size> [<dev_path> <offset>]+ 931da177e4SLinus Torvalds */ 941da177e4SLinus Torvalds static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) 951da177e4SLinus Torvalds { 961da177e4SLinus Torvalds struct stripe_c *sc; 971da177e4SLinus Torvalds sector_t width; 981da177e4SLinus Torvalds uint32_t stripes; 991da177e4SLinus Torvalds uint32_t chunk_size; 1001da177e4SLinus Torvalds int r; 1011da177e4SLinus Torvalds unsigned int i; 1021da177e4SLinus Torvalds 1031da177e4SLinus Torvalds if (argc < 2) { 10472d94861SAlasdair G Kergon ti->error = "Not enough arguments"; 1051da177e4SLinus Torvalds return -EINVAL; 1061da177e4SLinus Torvalds } 1071da177e4SLinus Torvalds 1081a66a08aSmajianpeng if (kstrtouint(argv[0], 10, &stripes) || !stripes) { 10972d94861SAlasdair G Kergon ti->error = "Invalid stripe count"; 1101da177e4SLinus Torvalds return -EINVAL; 1111da177e4SLinus Torvalds } 1121da177e4SLinus Torvalds 1138f069b41SMikulas Patocka if (kstrtouint(argv[1], 10, &chunk_size) || !chunk_size) { 11472d94861SAlasdair G Kergon ti->error = "Invalid chunk_size"; 1151da177e4SLinus Torvalds return -EINVAL; 1161da177e4SLinus Torvalds } 1171da177e4SLinus Torvalds 118eb850de6SMike Snitzer width = ti->len; 119eb850de6SMike Snitzer if (sector_div(width, chunk_size)) { 12072d94861SAlasdair G Kergon ti->error = "Target length not divisible by " 1218ba32fdeSKevin Corry "chunk size"; 1228ba32fdeSKevin Corry return -EINVAL; 1238ba32fdeSKevin Corry } 1248ba32fdeSKevin Corry 1251da177e4SLinus Torvalds if (sector_div(width, stripes)) { 12672d94861SAlasdair G Kergon ti->error = "Target length not divisible by " 1271da177e4SLinus Torvalds "number of stripes"; 1281da177e4SLinus Torvalds return -EINVAL; 1291da177e4SLinus Torvalds } 1301da177e4SLinus Torvalds 1311da177e4SLinus Torvalds /* 1321da177e4SLinus Torvalds * Do we have enough arguments for that many stripes ? 1331da177e4SLinus Torvalds */ 1341da177e4SLinus Torvalds if (argc != (2 + 2 * stripes)) { 13572d94861SAlasdair G Kergon ti->error = "Not enough destinations " 1361da177e4SLinus Torvalds "specified"; 1371da177e4SLinus Torvalds return -EINVAL; 1381da177e4SLinus Torvalds } 1391da177e4SLinus Torvalds 1401da177e4SLinus Torvalds sc = alloc_context(stripes); 1411da177e4SLinus Torvalds if (!sc) { 14272d94861SAlasdair G Kergon ti->error = "Memory allocation for striped context " 1431da177e4SLinus Torvalds "failed"; 1441da177e4SLinus Torvalds return -ENOMEM; 1451da177e4SLinus Torvalds } 1461da177e4SLinus Torvalds 147f521f074STejun Heo INIT_WORK(&sc->trigger_event, trigger_event); 148a25eb944SBrian Wood 149a25eb944SBrian Wood /* Set pointer to dm target; used in trigger_event */ 150a25eb944SBrian Wood sc->ti = ti; 1511da177e4SLinus Torvalds sc->stripes = stripes; 1521da177e4SLinus Torvalds sc->stripe_width = width; 153c96053b7SMikulas Patocka 154c96053b7SMikulas Patocka if (stripes & (stripes - 1)) 155c96053b7SMikulas Patocka sc->stripes_shift = -1; 1561df05483SMikulas Patocka else 1571df05483SMikulas Patocka sc->stripes_shift = __ffs(stripes); 158c96053b7SMikulas Patocka 159542f9038SMike Snitzer r = dm_set_target_max_io_len(ti, chunk_size); 160542f9038SMike Snitzer if (r) 161542f9038SMike Snitzer return r; 162542f9038SMike Snitzer 163374bf7e7SMikulas Patocka ti->num_flush_requests = stripes; 1647b76ec11SMikulas Patocka ti->num_discard_requests = stripes; 1651da177e4SLinus Torvalds 166eb850de6SMike Snitzer sc->chunk_size = chunk_size; 16733d07c0dSMikulas Patocka if (chunk_size & (chunk_size - 1)) 16833d07c0dSMikulas Patocka sc->chunk_size_shift = -1; 16933d07c0dSMikulas Patocka else 17033d07c0dSMikulas Patocka sc->chunk_size_shift = __ffs(chunk_size); 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds /* 1731da177e4SLinus Torvalds * Get the stripe destinations. 1741da177e4SLinus Torvalds */ 1751da177e4SLinus Torvalds for (i = 0; i < stripes; i++) { 1761da177e4SLinus Torvalds argv += 2; 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds r = get_stripe(ti, sc, i, argv); 1791da177e4SLinus Torvalds if (r < 0) { 18072d94861SAlasdair G Kergon ti->error = "Couldn't parse stripe destination"; 1811da177e4SLinus Torvalds while (i--) 1821da177e4SLinus Torvalds dm_put_device(ti, sc->stripe[i].dev); 1831da177e4SLinus Torvalds kfree(sc); 1841da177e4SLinus Torvalds return r; 1851da177e4SLinus Torvalds } 186a25eb944SBrian Wood atomic_set(&(sc->stripe[i].error_count), 0); 1871da177e4SLinus Torvalds } 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds ti->private = sc; 190a25eb944SBrian Wood 1911da177e4SLinus Torvalds return 0; 1921da177e4SLinus Torvalds } 1931da177e4SLinus Torvalds 1941da177e4SLinus Torvalds static void stripe_dtr(struct dm_target *ti) 1951da177e4SLinus Torvalds { 1961da177e4SLinus Torvalds unsigned int i; 1971da177e4SLinus Torvalds struct stripe_c *sc = (struct stripe_c *) ti->private; 1981da177e4SLinus Torvalds 1991da177e4SLinus Torvalds for (i = 0; i < sc->stripes; i++) 2001da177e4SLinus Torvalds dm_put_device(ti, sc->stripe[i].dev); 2011da177e4SLinus Torvalds 20243829731STejun Heo flush_work(&sc->trigger_event); 2031da177e4SLinus Torvalds kfree(sc); 2041da177e4SLinus Torvalds } 2051da177e4SLinus Torvalds 20665988525SMikulas Patocka static void stripe_map_sector(struct stripe_c *sc, sector_t sector, 20765988525SMikulas Patocka uint32_t *stripe, sector_t *result) 20865988525SMikulas Patocka { 209eb850de6SMike Snitzer sector_t chunk = dm_target_offset(sc->ti, sector); 21033d07c0dSMikulas Patocka sector_t chunk_offset; 21133d07c0dSMikulas Patocka 21233d07c0dSMikulas Patocka if (sc->chunk_size_shift < 0) 21333d07c0dSMikulas Patocka chunk_offset = sector_div(chunk, sc->chunk_size); 21433d07c0dSMikulas Patocka else { 21533d07c0dSMikulas Patocka chunk_offset = chunk & (sc->chunk_size - 1); 21633d07c0dSMikulas Patocka chunk >>= sc->chunk_size_shift; 21733d07c0dSMikulas Patocka } 21865988525SMikulas Patocka 219c96053b7SMikulas Patocka if (sc->stripes_shift < 0) 22065988525SMikulas Patocka *stripe = sector_div(chunk, sc->stripes); 221c96053b7SMikulas Patocka else { 2221df05483SMikulas Patocka *stripe = chunk & (sc->stripes - 1); 223c96053b7SMikulas Patocka chunk >>= sc->stripes_shift; 224c96053b7SMikulas Patocka } 225c96053b7SMikulas Patocka 22633d07c0dSMikulas Patocka if (sc->chunk_size_shift < 0) 22733d07c0dSMikulas Patocka chunk *= sc->chunk_size; 22833d07c0dSMikulas Patocka else 22933d07c0dSMikulas Patocka chunk <<= sc->chunk_size_shift; 23033d07c0dSMikulas Patocka 23133d07c0dSMikulas Patocka *result = chunk + chunk_offset; 23265988525SMikulas Patocka } 23365988525SMikulas Patocka 2347b76ec11SMikulas Patocka static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector, 2357b76ec11SMikulas Patocka uint32_t target_stripe, sector_t *result) 2367b76ec11SMikulas Patocka { 2377b76ec11SMikulas Patocka uint32_t stripe; 2387b76ec11SMikulas Patocka 2397b76ec11SMikulas Patocka stripe_map_sector(sc, sector, &stripe, result); 2407b76ec11SMikulas Patocka if (stripe == target_stripe) 2417b76ec11SMikulas Patocka return; 242eb850de6SMike Snitzer 243eb850de6SMike Snitzer /* round down */ 244eb850de6SMike Snitzer sector = *result; 24533d07c0dSMikulas Patocka if (sc->chunk_size_shift < 0) 246eb850de6SMike Snitzer *result -= sector_div(sector, sc->chunk_size); 24733d07c0dSMikulas Patocka else 24833d07c0dSMikulas Patocka *result = sector & ~(sector_t)(sc->chunk_size - 1); 249eb850de6SMike Snitzer 2507b76ec11SMikulas Patocka if (target_stripe < stripe) 251eb850de6SMike Snitzer *result += sc->chunk_size; /* next chunk */ 2527b76ec11SMikulas Patocka } 2537b76ec11SMikulas Patocka 2547b76ec11SMikulas Patocka static int stripe_map_discard(struct stripe_c *sc, struct bio *bio, 2557b76ec11SMikulas Patocka uint32_t target_stripe) 2567b76ec11SMikulas Patocka { 2577b76ec11SMikulas Patocka sector_t begin, end; 2587b76ec11SMikulas Patocka 2597b76ec11SMikulas Patocka stripe_map_range_sector(sc, bio->bi_sector, target_stripe, &begin); 2607b76ec11SMikulas Patocka stripe_map_range_sector(sc, bio->bi_sector + bio_sectors(bio), 2617b76ec11SMikulas Patocka target_stripe, &end); 2627b76ec11SMikulas Patocka if (begin < end) { 2637b76ec11SMikulas Patocka bio->bi_bdev = sc->stripe[target_stripe].dev->bdev; 2647b76ec11SMikulas Patocka bio->bi_sector = begin + sc->stripe[target_stripe].physical_start; 2657b76ec11SMikulas Patocka bio->bi_size = to_bytes(end - begin); 2667b76ec11SMikulas Patocka return DM_MAPIO_REMAPPED; 2677b76ec11SMikulas Patocka } else { 2687b76ec11SMikulas Patocka /* The range doesn't map to the target stripe */ 2697b76ec11SMikulas Patocka bio_endio(bio, 0); 2707b76ec11SMikulas Patocka return DM_MAPIO_SUBMITTED; 2717b76ec11SMikulas Patocka } 2727b76ec11SMikulas Patocka } 2737b76ec11SMikulas Patocka 2741da177e4SLinus Torvalds static int stripe_map(struct dm_target *ti, struct bio *bio, 2751da177e4SLinus Torvalds union map_info *map_context) 2761da177e4SLinus Torvalds { 27765988525SMikulas Patocka struct stripe_c *sc = ti->private; 278374bf7e7SMikulas Patocka uint32_t stripe; 27957cba5d3SMike Snitzer unsigned target_request_nr; 2801da177e4SLinus Torvalds 281d87f4c14STejun Heo if (bio->bi_rw & REQ_FLUSH) { 282ddbd658fSMikulas Patocka target_request_nr = dm_bio_get_target_request_nr(bio); 28357cba5d3SMike Snitzer BUG_ON(target_request_nr >= sc->stripes); 28457cba5d3SMike Snitzer bio->bi_bdev = sc->stripe[target_request_nr].dev->bdev; 285374bf7e7SMikulas Patocka return DM_MAPIO_REMAPPED; 286374bf7e7SMikulas Patocka } 2877b76ec11SMikulas Patocka if (unlikely(bio->bi_rw & REQ_DISCARD)) { 288ddbd658fSMikulas Patocka target_request_nr = dm_bio_get_target_request_nr(bio); 2897b76ec11SMikulas Patocka BUG_ON(target_request_nr >= sc->stripes); 2907b76ec11SMikulas Patocka return stripe_map_discard(sc, bio, target_request_nr); 2917b76ec11SMikulas Patocka } 292374bf7e7SMikulas Patocka 29365988525SMikulas Patocka stripe_map_sector(sc, bio->bi_sector, &stripe, &bio->bi_sector); 2941da177e4SLinus Torvalds 29565988525SMikulas Patocka bio->bi_sector += sc->stripe[stripe].physical_start; 2961da177e4SLinus Torvalds bio->bi_bdev = sc->stripe[stripe].dev->bdev; 29765988525SMikulas Patocka 298d2a7ad29SKiyoshi Ueda return DM_MAPIO_REMAPPED; 2991da177e4SLinus Torvalds } 3001da177e4SLinus Torvalds 3014f7f5c67SBrian Wood /* 3024f7f5c67SBrian Wood * Stripe status: 3034f7f5c67SBrian Wood * 3044f7f5c67SBrian Wood * INFO 3054f7f5c67SBrian Wood * #stripes [stripe_name <stripe_name>] [group word count] 3064f7f5c67SBrian Wood * [error count 'A|D' <error count 'A|D'>] 3074f7f5c67SBrian Wood * 3084f7f5c67SBrian Wood * TABLE 3094f7f5c67SBrian Wood * #stripes [stripe chunk size] 3104f7f5c67SBrian Wood * [stripe_name physical_start <stripe_name physical_start>] 3114f7f5c67SBrian Wood * 3124f7f5c67SBrian Wood */ 3134f7f5c67SBrian Wood 3141f4e0ff0SAlasdair G Kergon static int stripe_status(struct dm_target *ti, status_type_t type, 3151f4e0ff0SAlasdair G Kergon unsigned status_flags, char *result, unsigned maxlen) 3161da177e4SLinus Torvalds { 3171da177e4SLinus Torvalds struct stripe_c *sc = (struct stripe_c *) ti->private; 3184f7f5c67SBrian Wood char buffer[sc->stripes + 1]; 3191da177e4SLinus Torvalds unsigned int sz = 0; 3201da177e4SLinus Torvalds unsigned int i; 3211da177e4SLinus Torvalds 3221da177e4SLinus Torvalds switch (type) { 3231da177e4SLinus Torvalds case STATUSTYPE_INFO: 3244f7f5c67SBrian Wood DMEMIT("%d ", sc->stripes); 3254f7f5c67SBrian Wood for (i = 0; i < sc->stripes; i++) { 3264f7f5c67SBrian Wood DMEMIT("%s ", sc->stripe[i].dev->name); 3274f7f5c67SBrian Wood buffer[i] = atomic_read(&(sc->stripe[i].error_count)) ? 3284f7f5c67SBrian Wood 'D' : 'A'; 3294f7f5c67SBrian Wood } 3304f7f5c67SBrian Wood buffer[i] = '\0'; 3314f7f5c67SBrian Wood DMEMIT("1 %s", buffer); 3321da177e4SLinus Torvalds break; 3331da177e4SLinus Torvalds 3341da177e4SLinus Torvalds case STATUSTYPE_TABLE: 3354ee218cdSAndrew Morton DMEMIT("%d %llu", sc->stripes, 336eb850de6SMike Snitzer (unsigned long long)sc->chunk_size); 3371da177e4SLinus Torvalds for (i = 0; i < sc->stripes; i++) 3384ee218cdSAndrew Morton DMEMIT(" %s %llu", sc->stripe[i].dev->name, 3394ee218cdSAndrew Morton (unsigned long long)sc->stripe[i].physical_start); 3401da177e4SLinus Torvalds break; 3411da177e4SLinus Torvalds } 3421da177e4SLinus Torvalds return 0; 3431da177e4SLinus Torvalds } 3441da177e4SLinus Torvalds 345a25eb944SBrian Wood static int stripe_end_io(struct dm_target *ti, struct bio *bio, 346a25eb944SBrian Wood int error, union map_info *map_context) 347a25eb944SBrian Wood { 348a25eb944SBrian Wood unsigned i; 349a25eb944SBrian Wood char major_minor[16]; 350a25eb944SBrian Wood struct stripe_c *sc = ti->private; 351a25eb944SBrian Wood 352a25eb944SBrian Wood if (!error) 353a25eb944SBrian Wood return 0; /* I/O complete */ 354a25eb944SBrian Wood 3557b6d91daSChristoph Hellwig if ((error == -EWOULDBLOCK) && (bio->bi_rw & REQ_RAHEAD)) 356a25eb944SBrian Wood return error; 357a25eb944SBrian Wood 358a25eb944SBrian Wood if (error == -EOPNOTSUPP) 359a25eb944SBrian Wood return error; 360a25eb944SBrian Wood 361a25eb944SBrian Wood memset(major_minor, 0, sizeof(major_minor)); 362a25eb944SBrian Wood sprintf(major_minor, "%d:%d", 363f331c029STejun Heo MAJOR(disk_devt(bio->bi_bdev->bd_disk)), 364f331c029STejun Heo MINOR(disk_devt(bio->bi_bdev->bd_disk))); 365a25eb944SBrian Wood 366a25eb944SBrian Wood /* 367a25eb944SBrian Wood * Test to see which stripe drive triggered the event 368a25eb944SBrian Wood * and increment error count for all stripes on that device. 369a25eb944SBrian Wood * If the error count for a given device exceeds the threshold 370a25eb944SBrian Wood * value we will no longer trigger any further events. 371a25eb944SBrian Wood */ 372a25eb944SBrian Wood for (i = 0; i < sc->stripes; i++) 373a25eb944SBrian Wood if (!strcmp(sc->stripe[i].dev->name, major_minor)) { 374a25eb944SBrian Wood atomic_inc(&(sc->stripe[i].error_count)); 375a25eb944SBrian Wood if (atomic_read(&(sc->stripe[i].error_count)) < 376a25eb944SBrian Wood DM_IO_ERROR_THRESHOLD) 377f521f074STejun Heo schedule_work(&sc->trigger_event); 378a25eb944SBrian Wood } 379a25eb944SBrian Wood 380a25eb944SBrian Wood return error; 381a25eb944SBrian Wood } 382a25eb944SBrian Wood 383af4874e0SMike Snitzer static int stripe_iterate_devices(struct dm_target *ti, 384af4874e0SMike Snitzer iterate_devices_callout_fn fn, void *data) 385af4874e0SMike Snitzer { 386af4874e0SMike Snitzer struct stripe_c *sc = ti->private; 387af4874e0SMike Snitzer int ret = 0; 388af4874e0SMike Snitzer unsigned i = 0; 389af4874e0SMike Snitzer 3905dea271bSMike Snitzer do { 391af4874e0SMike Snitzer ret = fn(ti, sc->stripe[i].dev, 3925dea271bSMike Snitzer sc->stripe[i].physical_start, 3935dea271bSMike Snitzer sc->stripe_width, data); 3945dea271bSMike Snitzer } while (!ret && ++i < sc->stripes); 395af4874e0SMike Snitzer 396af4874e0SMike Snitzer return ret; 397af4874e0SMike Snitzer } 398af4874e0SMike Snitzer 39940bea431SMike Snitzer static void stripe_io_hints(struct dm_target *ti, 40040bea431SMike Snitzer struct queue_limits *limits) 40140bea431SMike Snitzer { 40240bea431SMike Snitzer struct stripe_c *sc = ti->private; 403eb850de6SMike Snitzer unsigned chunk_size = sc->chunk_size << SECTOR_SHIFT; 40440bea431SMike Snitzer 40540bea431SMike Snitzer blk_limits_io_min(limits, chunk_size); 4063c5820c7SMartin K. Petersen blk_limits_io_opt(limits, chunk_size * sc->stripes); 40740bea431SMike Snitzer } 40840bea431SMike Snitzer 40929915202SMustafa Mesanovic static int stripe_merge(struct dm_target *ti, struct bvec_merge_data *bvm, 41029915202SMustafa Mesanovic struct bio_vec *biovec, int max_size) 41129915202SMustafa Mesanovic { 41229915202SMustafa Mesanovic struct stripe_c *sc = ti->private; 41329915202SMustafa Mesanovic sector_t bvm_sector = bvm->bi_sector; 41429915202SMustafa Mesanovic uint32_t stripe; 41529915202SMustafa Mesanovic struct request_queue *q; 41629915202SMustafa Mesanovic 41729915202SMustafa Mesanovic stripe_map_sector(sc, bvm_sector, &stripe, &bvm_sector); 41829915202SMustafa Mesanovic 41929915202SMustafa Mesanovic q = bdev_get_queue(sc->stripe[stripe].dev->bdev); 42029915202SMustafa Mesanovic if (!q->merge_bvec_fn) 42129915202SMustafa Mesanovic return max_size; 42229915202SMustafa Mesanovic 42329915202SMustafa Mesanovic bvm->bi_bdev = sc->stripe[stripe].dev->bdev; 42429915202SMustafa Mesanovic bvm->bi_sector = sc->stripe[stripe].physical_start + bvm_sector; 42529915202SMustafa Mesanovic 42629915202SMustafa Mesanovic return min(max_size, q->merge_bvec_fn(q, bvm, biovec)); 42729915202SMustafa Mesanovic } 42829915202SMustafa Mesanovic 4291da177e4SLinus Torvalds static struct target_type stripe_target = { 4301da177e4SLinus Torvalds .name = "striped", 431eb850de6SMike Snitzer .version = {1, 5, 0}, 4321da177e4SLinus Torvalds .module = THIS_MODULE, 4331da177e4SLinus Torvalds .ctr = stripe_ctr, 4341da177e4SLinus Torvalds .dtr = stripe_dtr, 4351da177e4SLinus Torvalds .map = stripe_map, 436a25eb944SBrian Wood .end_io = stripe_end_io, 4371da177e4SLinus Torvalds .status = stripe_status, 438af4874e0SMike Snitzer .iterate_devices = stripe_iterate_devices, 43940bea431SMike Snitzer .io_hints = stripe_io_hints, 44029915202SMustafa Mesanovic .merge = stripe_merge, 4411da177e4SLinus Torvalds }; 4421da177e4SLinus Torvalds 4431da177e4SLinus Torvalds int __init dm_stripe_init(void) 4441da177e4SLinus Torvalds { 4451da177e4SLinus Torvalds int r; 4461da177e4SLinus Torvalds 4471da177e4SLinus Torvalds r = dm_register_target(&stripe_target); 4486edebdeeSHeinz Mauelshagen if (r < 0) { 44972d94861SAlasdair G Kergon DMWARN("target registration failed"); 4506edebdeeSHeinz Mauelshagen return r; 4516edebdeeSHeinz Mauelshagen } 4521da177e4SLinus Torvalds 4531da177e4SLinus Torvalds return r; 4541da177e4SLinus Torvalds } 4551da177e4SLinus Torvalds 4561da177e4SLinus Torvalds void dm_stripe_exit(void) 4571da177e4SLinus Torvalds { 45810d3bd09SMikulas Patocka dm_unregister_target(&stripe_target); 4591da177e4SLinus Torvalds } 460