dm-stripe.c revision 65988525abde0b0a5833c4e20f32967184a5dcf0
1/* 2 * Copyright (C) 2001-2003 Sistina Software (UK) Limited. 3 * 4 * This file is released under the GPL. 5 */ 6 7#include <linux/device-mapper.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#define DM_IO_ERROR_THRESHOLD 15 18 19struct stripe { 20 struct dm_dev *dev; 21 sector_t physical_start; 22 23 atomic_t error_count; 24}; 25 26struct stripe_c { 27 uint32_t stripes; 28 29 /* The size of this target / num. stripes */ 30 sector_t stripe_width; 31 32 /* stripe chunk size */ 33 uint32_t chunk_shift; 34 sector_t chunk_mask; 35 36 /* Needed for handling events */ 37 struct dm_target *ti; 38 39 /* Work struct used for triggering events*/ 40 struct work_struct kstriped_ws; 41 42 struct stripe stripe[0]; 43}; 44 45static struct workqueue_struct *kstriped; 46 47/* 48 * An event is triggered whenever a drive 49 * drops out of a stripe volume. 50 */ 51static void trigger_event(struct work_struct *work) 52{ 53 struct stripe_c *sc = container_of(work, struct stripe_c, kstriped_ws); 54 55 dm_table_event(sc->ti->table); 56 57} 58 59static inline struct stripe_c *alloc_context(unsigned int stripes) 60{ 61 size_t len; 62 63 if (dm_array_too_big(sizeof(struct stripe_c), sizeof(struct stripe), 64 stripes)) 65 return NULL; 66 67 len = sizeof(struct stripe_c) + (sizeof(struct stripe) * stripes); 68 69 return kmalloc(len, GFP_KERNEL); 70} 71 72/* 73 * Parse a single <dev> <sector> pair 74 */ 75static int get_stripe(struct dm_target *ti, struct stripe_c *sc, 76 unsigned int stripe, char **argv) 77{ 78 unsigned long long start; 79 80 if (sscanf(argv[1], "%llu", &start) != 1) 81 return -EINVAL; 82 83 if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), 84 &sc->stripe[stripe].dev)) 85 return -ENXIO; 86 87 sc->stripe[stripe].physical_start = start; 88 89 return 0; 90} 91 92/* 93 * Construct a striped mapping. 94 * <number of stripes> <chunk size (2^^n)> [<dev_path> <offset>]+ 95 */ 96static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) 97{ 98 struct stripe_c *sc; 99 sector_t width; 100 uint32_t stripes; 101 uint32_t chunk_size; 102 char *end; 103 int r; 104 unsigned int i; 105 106 if (argc < 2) { 107 ti->error = "Not enough arguments"; 108 return -EINVAL; 109 } 110 111 stripes = simple_strtoul(argv[0], &end, 10); 112 if (!stripes || *end) { 113 ti->error = "Invalid stripe count"; 114 return -EINVAL; 115 } 116 117 chunk_size = simple_strtoul(argv[1], &end, 10); 118 if (*end) { 119 ti->error = "Invalid chunk_size"; 120 return -EINVAL; 121 } 122 123 /* 124 * chunk_size is a power of two 125 */ 126 if (!is_power_of_2(chunk_size) || 127 (chunk_size < (PAGE_SIZE >> SECTOR_SHIFT))) { 128 ti->error = "Invalid chunk size"; 129 return -EINVAL; 130 } 131 132 if (ti->len & (chunk_size - 1)) { 133 ti->error = "Target length not divisible by " 134 "chunk size"; 135 return -EINVAL; 136 } 137 138 width = ti->len; 139 if (sector_div(width, stripes)) { 140 ti->error = "Target length not divisible by " 141 "number of stripes"; 142 return -EINVAL; 143 } 144 145 /* 146 * Do we have enough arguments for that many stripes ? 147 */ 148 if (argc != (2 + 2 * stripes)) { 149 ti->error = "Not enough destinations " 150 "specified"; 151 return -EINVAL; 152 } 153 154 sc = alloc_context(stripes); 155 if (!sc) { 156 ti->error = "Memory allocation for striped context " 157 "failed"; 158 return -ENOMEM; 159 } 160 161 INIT_WORK(&sc->kstriped_ws, trigger_event); 162 163 /* Set pointer to dm target; used in trigger_event */ 164 sc->ti = ti; 165 166 sc->stripes = stripes; 167 sc->stripe_width = width; 168 ti->split_io = chunk_size; 169 ti->num_flush_requests = stripes; 170 171 sc->chunk_mask = ((sector_t) chunk_size) - 1; 172 for (sc->chunk_shift = 0; chunk_size; sc->chunk_shift++) 173 chunk_size >>= 1; 174 sc->chunk_shift--; 175 176 /* 177 * Get the stripe destinations. 178 */ 179 for (i = 0; i < stripes; i++) { 180 argv += 2; 181 182 r = get_stripe(ti, sc, i, argv); 183 if (r < 0) { 184 ti->error = "Couldn't parse stripe destination"; 185 while (i--) 186 dm_put_device(ti, sc->stripe[i].dev); 187 kfree(sc); 188 return r; 189 } 190 atomic_set(&(sc->stripe[i].error_count), 0); 191 } 192 193 ti->private = sc; 194 195 return 0; 196} 197 198static void stripe_dtr(struct dm_target *ti) 199{ 200 unsigned int i; 201 struct stripe_c *sc = (struct stripe_c *) ti->private; 202 203 for (i = 0; i < sc->stripes; i++) 204 dm_put_device(ti, sc->stripe[i].dev); 205 206 flush_workqueue(kstriped); 207 kfree(sc); 208} 209 210static void stripe_map_sector(struct stripe_c *sc, sector_t sector, 211 uint32_t *stripe, sector_t *result) 212{ 213 sector_t offset = dm_target_offset(sc->ti, sector); 214 sector_t chunk = offset >> sc->chunk_shift; 215 216 *stripe = sector_div(chunk, sc->stripes); 217 *result = (chunk << sc->chunk_shift) | (offset & sc->chunk_mask); 218} 219 220static int stripe_map(struct dm_target *ti, struct bio *bio, 221 union map_info *map_context) 222{ 223 struct stripe_c *sc = ti->private; 224 uint32_t stripe; 225 unsigned target_request_nr; 226 227 if (unlikely(bio_empty_barrier(bio))) { 228 target_request_nr = map_context->target_request_nr; 229 BUG_ON(target_request_nr >= sc->stripes); 230 bio->bi_bdev = sc->stripe[target_request_nr].dev->bdev; 231 return DM_MAPIO_REMAPPED; 232 } 233 234 stripe_map_sector(sc, bio->bi_sector, &stripe, &bio->bi_sector); 235 236 bio->bi_sector += sc->stripe[stripe].physical_start; 237 bio->bi_bdev = sc->stripe[stripe].dev->bdev; 238 239 return DM_MAPIO_REMAPPED; 240} 241 242/* 243 * Stripe status: 244 * 245 * INFO 246 * #stripes [stripe_name <stripe_name>] [group word count] 247 * [error count 'A|D' <error count 'A|D'>] 248 * 249 * TABLE 250 * #stripes [stripe chunk size] 251 * [stripe_name physical_start <stripe_name physical_start>] 252 * 253 */ 254 255static int stripe_status(struct dm_target *ti, 256 status_type_t type, char *result, unsigned int maxlen) 257{ 258 struct stripe_c *sc = (struct stripe_c *) ti->private; 259 char buffer[sc->stripes + 1]; 260 unsigned int sz = 0; 261 unsigned int i; 262 263 switch (type) { 264 case STATUSTYPE_INFO: 265 DMEMIT("%d ", sc->stripes); 266 for (i = 0; i < sc->stripes; i++) { 267 DMEMIT("%s ", sc->stripe[i].dev->name); 268 buffer[i] = atomic_read(&(sc->stripe[i].error_count)) ? 269 'D' : 'A'; 270 } 271 buffer[i] = '\0'; 272 DMEMIT("1 %s", buffer); 273 break; 274 275 case STATUSTYPE_TABLE: 276 DMEMIT("%d %llu", sc->stripes, 277 (unsigned long long)sc->chunk_mask + 1); 278 for (i = 0; i < sc->stripes; i++) 279 DMEMIT(" %s %llu", sc->stripe[i].dev->name, 280 (unsigned long long)sc->stripe[i].physical_start); 281 break; 282 } 283 return 0; 284} 285 286static int stripe_end_io(struct dm_target *ti, struct bio *bio, 287 int error, union map_info *map_context) 288{ 289 unsigned i; 290 char major_minor[16]; 291 struct stripe_c *sc = ti->private; 292 293 if (!error) 294 return 0; /* I/O complete */ 295 296 if ((error == -EWOULDBLOCK) && (bio->bi_rw & REQ_RAHEAD)) 297 return error; 298 299 if (error == -EOPNOTSUPP) 300 return error; 301 302 memset(major_minor, 0, sizeof(major_minor)); 303 sprintf(major_minor, "%d:%d", 304 MAJOR(disk_devt(bio->bi_bdev->bd_disk)), 305 MINOR(disk_devt(bio->bi_bdev->bd_disk))); 306 307 /* 308 * Test to see which stripe drive triggered the event 309 * and increment error count for all stripes on that device. 310 * If the error count for a given device exceeds the threshold 311 * value we will no longer trigger any further events. 312 */ 313 for (i = 0; i < sc->stripes; i++) 314 if (!strcmp(sc->stripe[i].dev->name, major_minor)) { 315 atomic_inc(&(sc->stripe[i].error_count)); 316 if (atomic_read(&(sc->stripe[i].error_count)) < 317 DM_IO_ERROR_THRESHOLD) 318 queue_work(kstriped, &sc->kstriped_ws); 319 } 320 321 return error; 322} 323 324static int stripe_iterate_devices(struct dm_target *ti, 325 iterate_devices_callout_fn fn, void *data) 326{ 327 struct stripe_c *sc = ti->private; 328 int ret = 0; 329 unsigned i = 0; 330 331 do { 332 ret = fn(ti, sc->stripe[i].dev, 333 sc->stripe[i].physical_start, 334 sc->stripe_width, data); 335 } while (!ret && ++i < sc->stripes); 336 337 return ret; 338} 339 340static void stripe_io_hints(struct dm_target *ti, 341 struct queue_limits *limits) 342{ 343 struct stripe_c *sc = ti->private; 344 unsigned chunk_size = (sc->chunk_mask + 1) << 9; 345 346 blk_limits_io_min(limits, chunk_size); 347 blk_limits_io_opt(limits, chunk_size * sc->stripes); 348} 349 350static struct target_type stripe_target = { 351 .name = "striped", 352 .version = {1, 3, 0}, 353 .module = THIS_MODULE, 354 .ctr = stripe_ctr, 355 .dtr = stripe_dtr, 356 .map = stripe_map, 357 .end_io = stripe_end_io, 358 .status = stripe_status, 359 .iterate_devices = stripe_iterate_devices, 360 .io_hints = stripe_io_hints, 361}; 362 363int __init dm_stripe_init(void) 364{ 365 int r; 366 367 r = dm_register_target(&stripe_target); 368 if (r < 0) { 369 DMWARN("target registration failed"); 370 return r; 371 } 372 373 kstriped = create_singlethread_workqueue("kstriped"); 374 if (!kstriped) { 375 DMERR("failed to create workqueue kstriped"); 376 dm_unregister_target(&stripe_target); 377 return -ENOMEM; 378 } 379 380 return r; 381} 382 383void dm_stripe_exit(void) 384{ 385 dm_unregister_target(&stripe_target); 386 destroy_workqueue(kstriped); 387 388 return; 389} 390