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 71da177e4SLinus Torvalds #include "dm.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> 141da177e4SLinus Torvalds 151da177e4SLinus Torvalds struct stripe { 161da177e4SLinus Torvalds struct dm_dev *dev; 171da177e4SLinus Torvalds sector_t physical_start; 181da177e4SLinus Torvalds }; 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds struct stripe_c { 211da177e4SLinus Torvalds uint32_t stripes; 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds /* The size of this target / num. stripes */ 241da177e4SLinus Torvalds sector_t stripe_width; 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds /* stripe chunk size */ 271da177e4SLinus Torvalds uint32_t chunk_shift; 281da177e4SLinus Torvalds sector_t chunk_mask; 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds struct stripe stripe[0]; 311da177e4SLinus Torvalds }; 321da177e4SLinus Torvalds 331da177e4SLinus Torvalds static inline struct stripe_c *alloc_context(unsigned int stripes) 341da177e4SLinus Torvalds { 351da177e4SLinus Torvalds size_t len; 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds if (array_too_big(sizeof(struct stripe_c), sizeof(struct stripe), 381da177e4SLinus Torvalds stripes)) 391da177e4SLinus Torvalds return NULL; 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds len = sizeof(struct stripe_c) + (sizeof(struct stripe) * stripes); 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds return kmalloc(len, GFP_KERNEL); 441da177e4SLinus Torvalds } 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds /* 471da177e4SLinus Torvalds * Parse a single <dev> <sector> pair 481da177e4SLinus Torvalds */ 491da177e4SLinus Torvalds static int get_stripe(struct dm_target *ti, struct stripe_c *sc, 501da177e4SLinus Torvalds unsigned int stripe, char **argv) 511da177e4SLinus Torvalds { 524ee218cdSAndrew Morton unsigned long long start; 531da177e4SLinus Torvalds 544ee218cdSAndrew Morton if (sscanf(argv[1], "%llu", &start) != 1) 551da177e4SLinus Torvalds return -EINVAL; 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds if (dm_get_device(ti, argv[0], start, sc->stripe_width, 581da177e4SLinus Torvalds dm_table_get_mode(ti->table), 591da177e4SLinus Torvalds &sc->stripe[stripe].dev)) 601da177e4SLinus Torvalds return -ENXIO; 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds sc->stripe[stripe].physical_start = start; 631da177e4SLinus Torvalds return 0; 641da177e4SLinus Torvalds } 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds /* 671da177e4SLinus Torvalds * Construct a striped mapping. 681da177e4SLinus Torvalds * <number of stripes> <chunk size (2^^n)> [<dev_path> <offset>]+ 691da177e4SLinus Torvalds */ 701da177e4SLinus Torvalds static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) 711da177e4SLinus Torvalds { 721da177e4SLinus Torvalds struct stripe_c *sc; 731da177e4SLinus Torvalds sector_t width; 741da177e4SLinus Torvalds uint32_t stripes; 751da177e4SLinus Torvalds uint32_t chunk_size; 761da177e4SLinus Torvalds char *end; 771da177e4SLinus Torvalds int r; 781da177e4SLinus Torvalds unsigned int i; 791da177e4SLinus Torvalds 801da177e4SLinus Torvalds if (argc < 2) { 811da177e4SLinus Torvalds ti->error = "dm-stripe: Not enough arguments"; 821da177e4SLinus Torvalds return -EINVAL; 831da177e4SLinus Torvalds } 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds stripes = simple_strtoul(argv[0], &end, 10); 861da177e4SLinus Torvalds if (*end) { 871da177e4SLinus Torvalds ti->error = "dm-stripe: Invalid stripe count"; 881da177e4SLinus Torvalds return -EINVAL; 891da177e4SLinus Torvalds } 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds chunk_size = simple_strtoul(argv[1], &end, 10); 921da177e4SLinus Torvalds if (*end) { 931da177e4SLinus Torvalds ti->error = "dm-stripe: Invalid chunk_size"; 941da177e4SLinus Torvalds return -EINVAL; 951da177e4SLinus Torvalds } 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds /* 981da177e4SLinus Torvalds * chunk_size is a power of two 991da177e4SLinus Torvalds */ 1001da177e4SLinus Torvalds if (!chunk_size || (chunk_size & (chunk_size - 1)) || 1011da177e4SLinus Torvalds (chunk_size < (PAGE_SIZE >> SECTOR_SHIFT))) { 1021da177e4SLinus Torvalds ti->error = "dm-stripe: Invalid chunk size"; 1031da177e4SLinus Torvalds return -EINVAL; 1041da177e4SLinus Torvalds } 1051da177e4SLinus Torvalds 1068ba32fdeSKevin Corry if (((uint32_t)ti->len) & (chunk_size - 1)) { 1078ba32fdeSKevin Corry ti->error = "dm-stripe: Target length not divisible by " 1088ba32fdeSKevin Corry "chunk size"; 1098ba32fdeSKevin Corry return -EINVAL; 1108ba32fdeSKevin Corry } 1118ba32fdeSKevin Corry 1121da177e4SLinus Torvalds width = ti->len; 1131da177e4SLinus Torvalds if (sector_div(width, stripes)) { 1148ba32fdeSKevin Corry ti->error = "dm-stripe: Target length not divisible by " 1151da177e4SLinus Torvalds "number of stripes"; 1161da177e4SLinus Torvalds return -EINVAL; 1171da177e4SLinus Torvalds } 1181da177e4SLinus Torvalds 1191da177e4SLinus Torvalds /* 1201da177e4SLinus Torvalds * Do we have enough arguments for that many stripes ? 1211da177e4SLinus Torvalds */ 1221da177e4SLinus Torvalds if (argc != (2 + 2 * stripes)) { 1231da177e4SLinus Torvalds ti->error = "dm-stripe: Not enough destinations " 1241da177e4SLinus Torvalds "specified"; 1251da177e4SLinus Torvalds return -EINVAL; 1261da177e4SLinus Torvalds } 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds sc = alloc_context(stripes); 1291da177e4SLinus Torvalds if (!sc) { 1301da177e4SLinus Torvalds ti->error = "dm-stripe: Memory allocation for striped context " 1311da177e4SLinus Torvalds "failed"; 1321da177e4SLinus Torvalds return -ENOMEM; 1331da177e4SLinus Torvalds } 1341da177e4SLinus Torvalds 1351da177e4SLinus Torvalds sc->stripes = stripes; 1361da177e4SLinus Torvalds sc->stripe_width = width; 1371da177e4SLinus Torvalds ti->split_io = chunk_size; 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds sc->chunk_mask = ((sector_t) chunk_size) - 1; 1401da177e4SLinus Torvalds for (sc->chunk_shift = 0; chunk_size; sc->chunk_shift++) 1411da177e4SLinus Torvalds chunk_size >>= 1; 1421da177e4SLinus Torvalds sc->chunk_shift--; 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds /* 1451da177e4SLinus Torvalds * Get the stripe destinations. 1461da177e4SLinus Torvalds */ 1471da177e4SLinus Torvalds for (i = 0; i < stripes; i++) { 1481da177e4SLinus Torvalds argv += 2; 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds r = get_stripe(ti, sc, i, argv); 1511da177e4SLinus Torvalds if (r < 0) { 1521da177e4SLinus Torvalds ti->error = "dm-stripe: Couldn't parse stripe " 1531da177e4SLinus Torvalds "destination"; 1541da177e4SLinus Torvalds while (i--) 1551da177e4SLinus Torvalds dm_put_device(ti, sc->stripe[i].dev); 1561da177e4SLinus Torvalds kfree(sc); 1571da177e4SLinus Torvalds return r; 1581da177e4SLinus Torvalds } 1591da177e4SLinus Torvalds } 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds ti->private = sc; 1621da177e4SLinus Torvalds return 0; 1631da177e4SLinus Torvalds } 1641da177e4SLinus Torvalds 1651da177e4SLinus Torvalds static void stripe_dtr(struct dm_target *ti) 1661da177e4SLinus Torvalds { 1671da177e4SLinus Torvalds unsigned int i; 1681da177e4SLinus Torvalds struct stripe_c *sc = (struct stripe_c *) ti->private; 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds for (i = 0; i < sc->stripes; i++) 1711da177e4SLinus Torvalds dm_put_device(ti, sc->stripe[i].dev); 1721da177e4SLinus Torvalds 1731da177e4SLinus Torvalds kfree(sc); 1741da177e4SLinus Torvalds } 1751da177e4SLinus Torvalds 1761da177e4SLinus Torvalds static int stripe_map(struct dm_target *ti, struct bio *bio, 1771da177e4SLinus Torvalds union map_info *map_context) 1781da177e4SLinus Torvalds { 1791da177e4SLinus Torvalds struct stripe_c *sc = (struct stripe_c *) ti->private; 1801da177e4SLinus Torvalds 1811da177e4SLinus Torvalds sector_t offset = bio->bi_sector - ti->begin; 1821da177e4SLinus Torvalds sector_t chunk = offset >> sc->chunk_shift; 1831da177e4SLinus Torvalds uint32_t stripe = sector_div(chunk, sc->stripes); 1841da177e4SLinus Torvalds 1851da177e4SLinus Torvalds bio->bi_bdev = sc->stripe[stripe].dev->bdev; 1861da177e4SLinus Torvalds bio->bi_sector = sc->stripe[stripe].physical_start + 1871da177e4SLinus Torvalds (chunk << sc->chunk_shift) + (offset & sc->chunk_mask); 1881da177e4SLinus Torvalds return 1; 1891da177e4SLinus Torvalds } 1901da177e4SLinus Torvalds 1911da177e4SLinus Torvalds static int stripe_status(struct dm_target *ti, 1921da177e4SLinus Torvalds status_type_t type, char *result, unsigned int maxlen) 1931da177e4SLinus Torvalds { 1941da177e4SLinus Torvalds struct stripe_c *sc = (struct stripe_c *) ti->private; 1951da177e4SLinus Torvalds unsigned int sz = 0; 1961da177e4SLinus Torvalds unsigned int i; 1971da177e4SLinus Torvalds 1981da177e4SLinus Torvalds switch (type) { 1991da177e4SLinus Torvalds case STATUSTYPE_INFO: 2001da177e4SLinus Torvalds result[0] = '\0'; 2011da177e4SLinus Torvalds break; 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds case STATUSTYPE_TABLE: 2044ee218cdSAndrew Morton DMEMIT("%d %llu", sc->stripes, 2054ee218cdSAndrew Morton (unsigned long long)sc->chunk_mask + 1); 2061da177e4SLinus Torvalds for (i = 0; i < sc->stripes; i++) 2074ee218cdSAndrew Morton DMEMIT(" %s %llu", sc->stripe[i].dev->name, 2084ee218cdSAndrew Morton (unsigned long long)sc->stripe[i].physical_start); 2091da177e4SLinus Torvalds break; 2101da177e4SLinus Torvalds } 2111da177e4SLinus Torvalds return 0; 2121da177e4SLinus Torvalds } 2131da177e4SLinus Torvalds 2141da177e4SLinus Torvalds static struct target_type stripe_target = { 2151da177e4SLinus Torvalds .name = "striped", 2161da177e4SLinus Torvalds .version= {1, 0, 2}, 2171da177e4SLinus Torvalds .module = THIS_MODULE, 2181da177e4SLinus Torvalds .ctr = stripe_ctr, 2191da177e4SLinus Torvalds .dtr = stripe_dtr, 2201da177e4SLinus Torvalds .map = stripe_map, 2211da177e4SLinus Torvalds .status = stripe_status, 2221da177e4SLinus Torvalds }; 2231da177e4SLinus Torvalds 2241da177e4SLinus Torvalds int __init dm_stripe_init(void) 2251da177e4SLinus Torvalds { 2261da177e4SLinus Torvalds int r; 2271da177e4SLinus Torvalds 2281da177e4SLinus Torvalds r = dm_register_target(&stripe_target); 2291da177e4SLinus Torvalds if (r < 0) 2301da177e4SLinus Torvalds DMWARN("striped target registration failed"); 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds return r; 2331da177e4SLinus Torvalds } 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds void dm_stripe_exit(void) 2361da177e4SLinus Torvalds { 2371da177e4SLinus Torvalds if (dm_unregister_target(&stripe_target)) 2381da177e4SLinus Torvalds DMWARN("striped target unregistration failed"); 2391da177e4SLinus Torvalds 2401da177e4SLinus Torvalds return; 2411da177e4SLinus Torvalds } 242