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; 16545e621d4SMike Snitzer ti->num_write_same_requests = stripes; 1661da177e4SLinus Torvalds 167eb850de6SMike Snitzer sc->chunk_size = chunk_size; 16833d07c0dSMikulas Patocka if (chunk_size & (chunk_size - 1)) 16933d07c0dSMikulas Patocka sc->chunk_size_shift = -1; 17033d07c0dSMikulas Patocka else 17133d07c0dSMikulas Patocka sc->chunk_size_shift = __ffs(chunk_size); 1721da177e4SLinus Torvalds 1731da177e4SLinus Torvalds /* 1741da177e4SLinus Torvalds * Get the stripe destinations. 1751da177e4SLinus Torvalds */ 1761da177e4SLinus Torvalds for (i = 0; i < stripes; i++) { 1771da177e4SLinus Torvalds argv += 2; 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds r = get_stripe(ti, sc, i, argv); 1801da177e4SLinus Torvalds if (r < 0) { 18172d94861SAlasdair G Kergon ti->error = "Couldn't parse stripe destination"; 1821da177e4SLinus Torvalds while (i--) 1831da177e4SLinus Torvalds dm_put_device(ti, sc->stripe[i].dev); 1841da177e4SLinus Torvalds kfree(sc); 1851da177e4SLinus Torvalds return r; 1861da177e4SLinus Torvalds } 187a25eb944SBrian Wood atomic_set(&(sc->stripe[i].error_count), 0); 1881da177e4SLinus Torvalds } 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds ti->private = sc; 191a25eb944SBrian Wood 1921da177e4SLinus Torvalds return 0; 1931da177e4SLinus Torvalds } 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds static void stripe_dtr(struct dm_target *ti) 1961da177e4SLinus Torvalds { 1971da177e4SLinus Torvalds unsigned int i; 1981da177e4SLinus Torvalds struct stripe_c *sc = (struct stripe_c *) ti->private; 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds for (i = 0; i < sc->stripes; i++) 2011da177e4SLinus Torvalds dm_put_device(ti, sc->stripe[i].dev); 2021da177e4SLinus Torvalds 20343829731STejun Heo flush_work(&sc->trigger_event); 2041da177e4SLinus Torvalds kfree(sc); 2051da177e4SLinus Torvalds } 2061da177e4SLinus Torvalds 20765988525SMikulas Patocka static void stripe_map_sector(struct stripe_c *sc, sector_t sector, 20865988525SMikulas Patocka uint32_t *stripe, sector_t *result) 20965988525SMikulas Patocka { 210eb850de6SMike Snitzer sector_t chunk = dm_target_offset(sc->ti, sector); 21133d07c0dSMikulas Patocka sector_t chunk_offset; 21233d07c0dSMikulas Patocka 21333d07c0dSMikulas Patocka if (sc->chunk_size_shift < 0) 21433d07c0dSMikulas Patocka chunk_offset = sector_div(chunk, sc->chunk_size); 21533d07c0dSMikulas Patocka else { 21633d07c0dSMikulas Patocka chunk_offset = chunk & (sc->chunk_size - 1); 21733d07c0dSMikulas Patocka chunk >>= sc->chunk_size_shift; 21833d07c0dSMikulas Patocka } 21965988525SMikulas Patocka 220c96053b7SMikulas Patocka if (sc->stripes_shift < 0) 22165988525SMikulas Patocka *stripe = sector_div(chunk, sc->stripes); 222c96053b7SMikulas Patocka else { 2231df05483SMikulas Patocka *stripe = chunk & (sc->stripes - 1); 224c96053b7SMikulas Patocka chunk >>= sc->stripes_shift; 225c96053b7SMikulas Patocka } 226c96053b7SMikulas Patocka 22733d07c0dSMikulas Patocka if (sc->chunk_size_shift < 0) 22833d07c0dSMikulas Patocka chunk *= sc->chunk_size; 22933d07c0dSMikulas Patocka else 23033d07c0dSMikulas Patocka chunk <<= sc->chunk_size_shift; 23133d07c0dSMikulas Patocka 23233d07c0dSMikulas Patocka *result = chunk + chunk_offset; 23365988525SMikulas Patocka } 23465988525SMikulas Patocka 2357b76ec11SMikulas Patocka static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector, 2367b76ec11SMikulas Patocka uint32_t target_stripe, sector_t *result) 2377b76ec11SMikulas Patocka { 2387b76ec11SMikulas Patocka uint32_t stripe; 2397b76ec11SMikulas Patocka 2407b76ec11SMikulas Patocka stripe_map_sector(sc, sector, &stripe, result); 2417b76ec11SMikulas Patocka if (stripe == target_stripe) 2427b76ec11SMikulas Patocka return; 243eb850de6SMike Snitzer 244eb850de6SMike Snitzer /* round down */ 245eb850de6SMike Snitzer sector = *result; 24633d07c0dSMikulas Patocka if (sc->chunk_size_shift < 0) 247eb850de6SMike Snitzer *result -= sector_div(sector, sc->chunk_size); 24833d07c0dSMikulas Patocka else 24933d07c0dSMikulas Patocka *result = sector & ~(sector_t)(sc->chunk_size - 1); 250eb850de6SMike Snitzer 2517b76ec11SMikulas Patocka if (target_stripe < stripe) 252eb850de6SMike Snitzer *result += sc->chunk_size; /* next chunk */ 2537b76ec11SMikulas Patocka } 2547b76ec11SMikulas Patocka 25545e621d4SMike Snitzer static int stripe_map_range(struct stripe_c *sc, struct bio *bio, 2567b76ec11SMikulas Patocka uint32_t target_stripe) 2577b76ec11SMikulas Patocka { 2587b76ec11SMikulas Patocka sector_t begin, end; 2597b76ec11SMikulas Patocka 2607b76ec11SMikulas Patocka stripe_map_range_sector(sc, bio->bi_sector, target_stripe, &begin); 2617b76ec11SMikulas Patocka stripe_map_range_sector(sc, bio->bi_sector + bio_sectors(bio), 2627b76ec11SMikulas Patocka target_stripe, &end); 2637b76ec11SMikulas Patocka if (begin < end) { 2647b76ec11SMikulas Patocka bio->bi_bdev = sc->stripe[target_stripe].dev->bdev; 2657b76ec11SMikulas Patocka bio->bi_sector = begin + sc->stripe[target_stripe].physical_start; 2667b76ec11SMikulas Patocka bio->bi_size = to_bytes(end - begin); 2677b76ec11SMikulas Patocka return DM_MAPIO_REMAPPED; 2687b76ec11SMikulas Patocka } else { 2697b76ec11SMikulas Patocka /* The range doesn't map to the target stripe */ 2707b76ec11SMikulas Patocka bio_endio(bio, 0); 2717b76ec11SMikulas Patocka return DM_MAPIO_SUBMITTED; 2727b76ec11SMikulas Patocka } 2737b76ec11SMikulas Patocka } 2747b76ec11SMikulas Patocka 2757de3ee57SMikulas Patocka static int stripe_map(struct dm_target *ti, struct bio *bio) 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 } 28745e621d4SMike Snitzer if (unlikely(bio->bi_rw & REQ_DISCARD) || 28845e621d4SMike Snitzer unlikely(bio->bi_rw & REQ_WRITE_SAME)) { 289ddbd658fSMikulas Patocka target_request_nr = dm_bio_get_target_request_nr(bio); 2907b76ec11SMikulas Patocka BUG_ON(target_request_nr >= sc->stripes); 29145e621d4SMike Snitzer return stripe_map_range(sc, bio, target_request_nr); 2927b76ec11SMikulas Patocka } 293374bf7e7SMikulas Patocka 29465988525SMikulas Patocka stripe_map_sector(sc, bio->bi_sector, &stripe, &bio->bi_sector); 2951da177e4SLinus Torvalds 29665988525SMikulas Patocka bio->bi_sector += sc->stripe[stripe].physical_start; 2971da177e4SLinus Torvalds bio->bi_bdev = sc->stripe[stripe].dev->bdev; 29865988525SMikulas Patocka 299d2a7ad29SKiyoshi Ueda return DM_MAPIO_REMAPPED; 3001da177e4SLinus Torvalds } 3011da177e4SLinus Torvalds 3024f7f5c67SBrian Wood /* 3034f7f5c67SBrian Wood * Stripe status: 3044f7f5c67SBrian Wood * 3054f7f5c67SBrian Wood * INFO 3064f7f5c67SBrian Wood * #stripes [stripe_name <stripe_name>] [group word count] 3074f7f5c67SBrian Wood * [error count 'A|D' <error count 'A|D'>] 3084f7f5c67SBrian Wood * 3094f7f5c67SBrian Wood * TABLE 3104f7f5c67SBrian Wood * #stripes [stripe chunk size] 3114f7f5c67SBrian Wood * [stripe_name physical_start <stripe_name physical_start>] 3124f7f5c67SBrian Wood * 3134f7f5c67SBrian Wood */ 3144f7f5c67SBrian Wood 315fd7c092eSMikulas Patocka static void stripe_status(struct dm_target *ti, status_type_t type, 3161f4e0ff0SAlasdair G Kergon unsigned status_flags, char *result, unsigned maxlen) 3171da177e4SLinus Torvalds { 3181da177e4SLinus Torvalds struct stripe_c *sc = (struct stripe_c *) ti->private; 3194f7f5c67SBrian Wood char buffer[sc->stripes + 1]; 3201da177e4SLinus Torvalds unsigned int sz = 0; 3211da177e4SLinus Torvalds unsigned int i; 3221da177e4SLinus Torvalds 3231da177e4SLinus Torvalds switch (type) { 3241da177e4SLinus Torvalds case STATUSTYPE_INFO: 3254f7f5c67SBrian Wood DMEMIT("%d ", sc->stripes); 3264f7f5c67SBrian Wood for (i = 0; i < sc->stripes; i++) { 3274f7f5c67SBrian Wood DMEMIT("%s ", sc->stripe[i].dev->name); 3284f7f5c67SBrian Wood buffer[i] = atomic_read(&(sc->stripe[i].error_count)) ? 3294f7f5c67SBrian Wood 'D' : 'A'; 3304f7f5c67SBrian Wood } 3314f7f5c67SBrian Wood buffer[i] = '\0'; 3324f7f5c67SBrian Wood DMEMIT("1 %s", buffer); 3331da177e4SLinus Torvalds break; 3341da177e4SLinus Torvalds 3351da177e4SLinus Torvalds case STATUSTYPE_TABLE: 3364ee218cdSAndrew Morton DMEMIT("%d %llu", sc->stripes, 337eb850de6SMike Snitzer (unsigned long long)sc->chunk_size); 3381da177e4SLinus Torvalds for (i = 0; i < sc->stripes; i++) 3394ee218cdSAndrew Morton DMEMIT(" %s %llu", sc->stripe[i].dev->name, 3404ee218cdSAndrew Morton (unsigned long long)sc->stripe[i].physical_start); 3411da177e4SLinus Torvalds break; 3421da177e4SLinus Torvalds } 3431da177e4SLinus Torvalds } 3441da177e4SLinus Torvalds 3457de3ee57SMikulas Patocka static int stripe_end_io(struct dm_target *ti, struct bio *bio, int error) 346a25eb944SBrian Wood { 347a25eb944SBrian Wood unsigned i; 348a25eb944SBrian Wood char major_minor[16]; 349a25eb944SBrian Wood struct stripe_c *sc = ti->private; 350a25eb944SBrian Wood 351a25eb944SBrian Wood if (!error) 352a25eb944SBrian Wood return 0; /* I/O complete */ 353a25eb944SBrian Wood 3547b6d91daSChristoph Hellwig if ((error == -EWOULDBLOCK) && (bio->bi_rw & REQ_RAHEAD)) 355a25eb944SBrian Wood return error; 356a25eb944SBrian Wood 357a25eb944SBrian Wood if (error == -EOPNOTSUPP) 358a25eb944SBrian Wood return error; 359a25eb944SBrian Wood 360a25eb944SBrian Wood memset(major_minor, 0, sizeof(major_minor)); 361a25eb944SBrian Wood sprintf(major_minor, "%d:%d", 362f331c029STejun Heo MAJOR(disk_devt(bio->bi_bdev->bd_disk)), 363f331c029STejun Heo MINOR(disk_devt(bio->bi_bdev->bd_disk))); 364a25eb944SBrian Wood 365a25eb944SBrian Wood /* 366a25eb944SBrian Wood * Test to see which stripe drive triggered the event 367a25eb944SBrian Wood * and increment error count for all stripes on that device. 368a25eb944SBrian Wood * If the error count for a given device exceeds the threshold 369a25eb944SBrian Wood * value we will no longer trigger any further events. 370a25eb944SBrian Wood */ 371a25eb944SBrian Wood for (i = 0; i < sc->stripes; i++) 372a25eb944SBrian Wood if (!strcmp(sc->stripe[i].dev->name, major_minor)) { 373a25eb944SBrian Wood atomic_inc(&(sc->stripe[i].error_count)); 374a25eb944SBrian Wood if (atomic_read(&(sc->stripe[i].error_count)) < 375a25eb944SBrian Wood DM_IO_ERROR_THRESHOLD) 376f521f074STejun Heo schedule_work(&sc->trigger_event); 377a25eb944SBrian Wood } 378a25eb944SBrian Wood 379a25eb944SBrian Wood return error; 380a25eb944SBrian Wood } 381a25eb944SBrian Wood 382af4874e0SMike Snitzer static int stripe_iterate_devices(struct dm_target *ti, 383af4874e0SMike Snitzer iterate_devices_callout_fn fn, void *data) 384af4874e0SMike Snitzer { 385af4874e0SMike Snitzer struct stripe_c *sc = ti->private; 386af4874e0SMike Snitzer int ret = 0; 387af4874e0SMike Snitzer unsigned i = 0; 388af4874e0SMike Snitzer 3895dea271bSMike Snitzer do { 390af4874e0SMike Snitzer ret = fn(ti, sc->stripe[i].dev, 3915dea271bSMike Snitzer sc->stripe[i].physical_start, 3925dea271bSMike Snitzer sc->stripe_width, data); 3935dea271bSMike Snitzer } while (!ret && ++i < sc->stripes); 394af4874e0SMike Snitzer 395af4874e0SMike Snitzer return ret; 396af4874e0SMike Snitzer } 397af4874e0SMike Snitzer 39840bea431SMike Snitzer static void stripe_io_hints(struct dm_target *ti, 39940bea431SMike Snitzer struct queue_limits *limits) 40040bea431SMike Snitzer { 40140bea431SMike Snitzer struct stripe_c *sc = ti->private; 402eb850de6SMike Snitzer unsigned chunk_size = sc->chunk_size << SECTOR_SHIFT; 40340bea431SMike Snitzer 40440bea431SMike Snitzer blk_limits_io_min(limits, chunk_size); 4053c5820c7SMartin K. Petersen blk_limits_io_opt(limits, chunk_size * sc->stripes); 40640bea431SMike Snitzer } 40740bea431SMike Snitzer 40829915202SMustafa Mesanovic static int stripe_merge(struct dm_target *ti, struct bvec_merge_data *bvm, 40929915202SMustafa Mesanovic struct bio_vec *biovec, int max_size) 41029915202SMustafa Mesanovic { 41129915202SMustafa Mesanovic struct stripe_c *sc = ti->private; 41229915202SMustafa Mesanovic sector_t bvm_sector = bvm->bi_sector; 41329915202SMustafa Mesanovic uint32_t stripe; 41429915202SMustafa Mesanovic struct request_queue *q; 41529915202SMustafa Mesanovic 41629915202SMustafa Mesanovic stripe_map_sector(sc, bvm_sector, &stripe, &bvm_sector); 41729915202SMustafa Mesanovic 41829915202SMustafa Mesanovic q = bdev_get_queue(sc->stripe[stripe].dev->bdev); 41929915202SMustafa Mesanovic if (!q->merge_bvec_fn) 42029915202SMustafa Mesanovic return max_size; 42129915202SMustafa Mesanovic 42229915202SMustafa Mesanovic bvm->bi_bdev = sc->stripe[stripe].dev->bdev; 42329915202SMustafa Mesanovic bvm->bi_sector = sc->stripe[stripe].physical_start + bvm_sector; 42429915202SMustafa Mesanovic 42529915202SMustafa Mesanovic return min(max_size, q->merge_bvec_fn(q, bvm, biovec)); 42629915202SMustafa Mesanovic } 42729915202SMustafa Mesanovic 4281da177e4SLinus Torvalds static struct target_type stripe_target = { 4291da177e4SLinus Torvalds .name = "striped", 430fd7c092eSMikulas Patocka .version = {1, 5, 1}, 4311da177e4SLinus Torvalds .module = THIS_MODULE, 4321da177e4SLinus Torvalds .ctr = stripe_ctr, 4331da177e4SLinus Torvalds .dtr = stripe_dtr, 4341da177e4SLinus Torvalds .map = stripe_map, 435a25eb944SBrian Wood .end_io = stripe_end_io, 4361da177e4SLinus Torvalds .status = stripe_status, 437af4874e0SMike Snitzer .iterate_devices = stripe_iterate_devices, 43840bea431SMike Snitzer .io_hints = stripe_io_hints, 43929915202SMustafa Mesanovic .merge = stripe_merge, 4401da177e4SLinus Torvalds }; 4411da177e4SLinus Torvalds 4421da177e4SLinus Torvalds int __init dm_stripe_init(void) 4431da177e4SLinus Torvalds { 4441da177e4SLinus Torvalds int r; 4451da177e4SLinus Torvalds 4461da177e4SLinus Torvalds r = dm_register_target(&stripe_target); 4476edebdeeSHeinz Mauelshagen if (r < 0) { 44872d94861SAlasdair G Kergon DMWARN("target registration failed"); 4496edebdeeSHeinz Mauelshagen return r; 4506edebdeeSHeinz Mauelshagen } 4511da177e4SLinus Torvalds 4521da177e4SLinus Torvalds return r; 4531da177e4SLinus Torvalds } 4541da177e4SLinus Torvalds 4551da177e4SLinus Torvalds void dm_stripe_exit(void) 4561da177e4SLinus Torvalds { 45710d3bd09SMikulas Patocka dm_unregister_target(&stripe_target); 4581da177e4SLinus Torvalds } 459