1 /* 2 * Copyright (C) 2001-2003 Sistina Software (UK) Limited. 3 * 4 * This file is released under the GPL. 5 */ 6 7 #include "dm.h" 8 9 #include <linux/module.h> 10 #include <linux/init.h> 11 #include <linux/blkdev.h> 12 #include <linux/bio.h> 13 #include <linux/slab.h> 14 15 struct stripe { 16 struct dm_dev *dev; 17 sector_t physical_start; 18 }; 19 20 struct stripe_c { 21 uint32_t stripes; 22 23 /* The size of this target / num. stripes */ 24 sector_t stripe_width; 25 26 /* stripe chunk size */ 27 uint32_t chunk_shift; 28 sector_t chunk_mask; 29 30 struct stripe stripe[0]; 31 }; 32 33 static inline struct stripe_c *alloc_context(unsigned int stripes) 34 { 35 size_t len; 36 37 if (array_too_big(sizeof(struct stripe_c), sizeof(struct stripe), 38 stripes)) 39 return NULL; 40 41 len = sizeof(struct stripe_c) + (sizeof(struct stripe) * stripes); 42 43 return kmalloc(len, GFP_KERNEL); 44 } 45 46 /* 47 * Parse a single <dev> <sector> pair 48 */ 49 static int get_stripe(struct dm_target *ti, struct stripe_c *sc, 50 unsigned int stripe, char **argv) 51 { 52 unsigned long long start; 53 54 if (sscanf(argv[1], "%llu", &start) != 1) 55 return -EINVAL; 56 57 if (dm_get_device(ti, argv[0], start, sc->stripe_width, 58 dm_table_get_mode(ti->table), 59 &sc->stripe[stripe].dev)) 60 return -ENXIO; 61 62 sc->stripe[stripe].physical_start = start; 63 return 0; 64 } 65 66 /* 67 * Construct a striped mapping. 68 * <number of stripes> <chunk size (2^^n)> [<dev_path> <offset>]+ 69 */ 70 static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) 71 { 72 struct stripe_c *sc; 73 sector_t width; 74 uint32_t stripes; 75 uint32_t chunk_size; 76 char *end; 77 int r; 78 unsigned int i; 79 80 if (argc < 2) { 81 ti->error = "dm-stripe: Not enough arguments"; 82 return -EINVAL; 83 } 84 85 stripes = simple_strtoul(argv[0], &end, 10); 86 if (*end) { 87 ti->error = "dm-stripe: Invalid stripe count"; 88 return -EINVAL; 89 } 90 91 chunk_size = simple_strtoul(argv[1], &end, 10); 92 if (*end) { 93 ti->error = "dm-stripe: Invalid chunk_size"; 94 return -EINVAL; 95 } 96 97 /* 98 * chunk_size is a power of two 99 */ 100 if (!chunk_size || (chunk_size & (chunk_size - 1)) || 101 (chunk_size < (PAGE_SIZE >> SECTOR_SHIFT))) { 102 ti->error = "dm-stripe: Invalid chunk size"; 103 return -EINVAL; 104 } 105 106 if (ti->len & (chunk_size - 1)) { 107 ti->error = "dm-stripe: Target length not divisible by " 108 "chunk size"; 109 return -EINVAL; 110 } 111 112 width = ti->len; 113 if (sector_div(width, stripes)) { 114 ti->error = "dm-stripe: Target length not divisible by " 115 "number of stripes"; 116 return -EINVAL; 117 } 118 119 /* 120 * Do we have enough arguments for that many stripes ? 121 */ 122 if (argc != (2 + 2 * stripes)) { 123 ti->error = "dm-stripe: Not enough destinations " 124 "specified"; 125 return -EINVAL; 126 } 127 128 sc = alloc_context(stripes); 129 if (!sc) { 130 ti->error = "dm-stripe: Memory allocation for striped context " 131 "failed"; 132 return -ENOMEM; 133 } 134 135 sc->stripes = stripes; 136 sc->stripe_width = width; 137 ti->split_io = chunk_size; 138 139 sc->chunk_mask = ((sector_t) chunk_size) - 1; 140 for (sc->chunk_shift = 0; chunk_size; sc->chunk_shift++) 141 chunk_size >>= 1; 142 sc->chunk_shift--; 143 144 /* 145 * Get the stripe destinations. 146 */ 147 for (i = 0; i < stripes; i++) { 148 argv += 2; 149 150 r = get_stripe(ti, sc, i, argv); 151 if (r < 0) { 152 ti->error = "dm-stripe: Couldn't parse stripe " 153 "destination"; 154 while (i--) 155 dm_put_device(ti, sc->stripe[i].dev); 156 kfree(sc); 157 return r; 158 } 159 } 160 161 ti->private = sc; 162 return 0; 163 } 164 165 static void stripe_dtr(struct dm_target *ti) 166 { 167 unsigned int i; 168 struct stripe_c *sc = (struct stripe_c *) ti->private; 169 170 for (i = 0; i < sc->stripes; i++) 171 dm_put_device(ti, sc->stripe[i].dev); 172 173 kfree(sc); 174 } 175 176 static int stripe_map(struct dm_target *ti, struct bio *bio, 177 union map_info *map_context) 178 { 179 struct stripe_c *sc = (struct stripe_c *) ti->private; 180 181 sector_t offset = bio->bi_sector - ti->begin; 182 sector_t chunk = offset >> sc->chunk_shift; 183 uint32_t stripe = sector_div(chunk, sc->stripes); 184 185 bio->bi_bdev = sc->stripe[stripe].dev->bdev; 186 bio->bi_sector = sc->stripe[stripe].physical_start + 187 (chunk << sc->chunk_shift) + (offset & sc->chunk_mask); 188 return 1; 189 } 190 191 static int stripe_status(struct dm_target *ti, 192 status_type_t type, char *result, unsigned int maxlen) 193 { 194 struct stripe_c *sc = (struct stripe_c *) ti->private; 195 unsigned int sz = 0; 196 unsigned int i; 197 198 switch (type) { 199 case STATUSTYPE_INFO: 200 result[0] = '\0'; 201 break; 202 203 case STATUSTYPE_TABLE: 204 DMEMIT("%d %llu", sc->stripes, 205 (unsigned long long)sc->chunk_mask + 1); 206 for (i = 0; i < sc->stripes; i++) 207 DMEMIT(" %s %llu", sc->stripe[i].dev->name, 208 (unsigned long long)sc->stripe[i].physical_start); 209 break; 210 } 211 return 0; 212 } 213 214 static struct target_type stripe_target = { 215 .name = "striped", 216 .version= {1, 0, 2}, 217 .module = THIS_MODULE, 218 .ctr = stripe_ctr, 219 .dtr = stripe_dtr, 220 .map = stripe_map, 221 .status = stripe_status, 222 }; 223 224 int __init dm_stripe_init(void) 225 { 226 int r; 227 228 r = dm_register_target(&stripe_target); 229 if (r < 0) 230 DMWARN("striped target registration failed"); 231 232 return r; 233 } 234 235 void dm_stripe_exit(void) 236 { 237 if (dm_unregister_target(&stripe_target)) 238 DMWARN("striped target unregistration failed"); 239 240 return; 241 } 242