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