dm-stripe.c revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2
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 15struct stripe { 16 struct dm_dev *dev; 17 sector_t physical_start; 18}; 19 20struct 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 33static 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 */ 49static int get_stripe(struct dm_target *ti, struct stripe_c *sc, 50 unsigned int stripe, char **argv) 51{ 52 sector_t start; 53 54 if (sscanf(argv[1], SECTOR_FORMAT, &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 */ 70static 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 width = ti->len; 107 if (sector_div(width, stripes)) { 108 ti->error = "dm-stripe: Target length not divisable by " 109 "number of stripes"; 110 return -EINVAL; 111 } 112 113 /* 114 * Do we have enough arguments for that many stripes ? 115 */ 116 if (argc != (2 + 2 * stripes)) { 117 ti->error = "dm-stripe: Not enough destinations " 118 "specified"; 119 return -EINVAL; 120 } 121 122 sc = alloc_context(stripes); 123 if (!sc) { 124 ti->error = "dm-stripe: Memory allocation for striped context " 125 "failed"; 126 return -ENOMEM; 127 } 128 129 sc->stripes = stripes; 130 sc->stripe_width = width; 131 ti->split_io = chunk_size; 132 133 sc->chunk_mask = ((sector_t) chunk_size) - 1; 134 for (sc->chunk_shift = 0; chunk_size; sc->chunk_shift++) 135 chunk_size >>= 1; 136 sc->chunk_shift--; 137 138 /* 139 * Get the stripe destinations. 140 */ 141 for (i = 0; i < stripes; i++) { 142 argv += 2; 143 144 r = get_stripe(ti, sc, i, argv); 145 if (r < 0) { 146 ti->error = "dm-stripe: Couldn't parse stripe " 147 "destination"; 148 while (i--) 149 dm_put_device(ti, sc->stripe[i].dev); 150 kfree(sc); 151 return r; 152 } 153 } 154 155 ti->private = sc; 156 return 0; 157} 158 159static void stripe_dtr(struct dm_target *ti) 160{ 161 unsigned int i; 162 struct stripe_c *sc = (struct stripe_c *) ti->private; 163 164 for (i = 0; i < sc->stripes; i++) 165 dm_put_device(ti, sc->stripe[i].dev); 166 167 kfree(sc); 168} 169 170static int stripe_map(struct dm_target *ti, struct bio *bio, 171 union map_info *map_context) 172{ 173 struct stripe_c *sc = (struct stripe_c *) ti->private; 174 175 sector_t offset = bio->bi_sector - ti->begin; 176 sector_t chunk = offset >> sc->chunk_shift; 177 uint32_t stripe = sector_div(chunk, sc->stripes); 178 179 bio->bi_bdev = sc->stripe[stripe].dev->bdev; 180 bio->bi_sector = sc->stripe[stripe].physical_start + 181 (chunk << sc->chunk_shift) + (offset & sc->chunk_mask); 182 return 1; 183} 184 185static int stripe_status(struct dm_target *ti, 186 status_type_t type, char *result, unsigned int maxlen) 187{ 188 struct stripe_c *sc = (struct stripe_c *) ti->private; 189 unsigned int sz = 0; 190 unsigned int i; 191 192 switch (type) { 193 case STATUSTYPE_INFO: 194 result[0] = '\0'; 195 break; 196 197 case STATUSTYPE_TABLE: 198 DMEMIT("%d " SECTOR_FORMAT, sc->stripes, sc->chunk_mask + 1); 199 for (i = 0; i < sc->stripes; i++) 200 DMEMIT(" %s " SECTOR_FORMAT, sc->stripe[i].dev->name, 201 sc->stripe[i].physical_start); 202 break; 203 } 204 return 0; 205} 206 207static struct target_type stripe_target = { 208 .name = "striped", 209 .version= {1, 0, 2}, 210 .module = THIS_MODULE, 211 .ctr = stripe_ctr, 212 .dtr = stripe_dtr, 213 .map = stripe_map, 214 .status = stripe_status, 215}; 216 217int __init dm_stripe_init(void) 218{ 219 int r; 220 221 r = dm_register_target(&stripe_target); 222 if (r < 0) 223 DMWARN("striped target registration failed"); 224 225 return r; 226} 227 228void dm_stripe_exit(void) 229{ 230 if (dm_unregister_target(&stripe_target)) 231 DMWARN("striped target unregistration failed"); 232 233 return; 234} 235