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