diff options
Diffstat (limited to 'drivers/md/dm-stripe.c')
-rw-r--r-- | drivers/md/dm-stripe.c | 87 |
1 files changed, 48 insertions, 39 deletions
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index 35c94ff24ad5..a087bf2a8d66 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c | |||
@@ -26,14 +26,12 @@ struct stripe { | |||
26 | struct stripe_c { | 26 | struct stripe_c { |
27 | uint32_t stripes; | 27 | uint32_t stripes; |
28 | int stripes_shift; | 28 | int stripes_shift; |
29 | sector_t stripes_mask; | ||
30 | 29 | ||
31 | /* The size of this target / num. stripes */ | 30 | /* The size of this target / num. stripes */ |
32 | sector_t stripe_width; | 31 | sector_t stripe_width; |
33 | 32 | ||
34 | /* stripe chunk size */ | 33 | uint32_t chunk_size; |
35 | uint32_t chunk_shift; | 34 | int chunk_size_shift; |
36 | sector_t chunk_mask; | ||
37 | 35 | ||
38 | /* Needed for handling events */ | 36 | /* Needed for handling events */ |
39 | struct dm_target *ti; | 37 | struct dm_target *ti; |
@@ -91,7 +89,7 @@ static int get_stripe(struct dm_target *ti, struct stripe_c *sc, | |||
91 | 89 | ||
92 | /* | 90 | /* |
93 | * Construct a striped mapping. | 91 | * Construct a striped mapping. |
94 | * <number of stripes> <chunk size (2^^n)> [<dev_path> <offset>]+ | 92 | * <number of stripes> <chunk size> [<dev_path> <offset>]+ |
95 | */ | 93 | */ |
96 | static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) | 94 | static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) |
97 | { | 95 | { |
@@ -99,7 +97,6 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
99 | sector_t width; | 97 | sector_t width; |
100 | uint32_t stripes; | 98 | uint32_t stripes; |
101 | uint32_t chunk_size; | 99 | uint32_t chunk_size; |
102 | char *end; | ||
103 | int r; | 100 | int r; |
104 | unsigned int i; | 101 | unsigned int i; |
105 | 102 | ||
@@ -108,34 +105,23 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
108 | return -EINVAL; | 105 | return -EINVAL; |
109 | } | 106 | } |
110 | 107 | ||
111 | stripes = simple_strtoul(argv[0], &end, 10); | 108 | if (kstrtouint(argv[0], 10, &stripes) || !stripes) { |
112 | if (!stripes || *end) { | ||
113 | ti->error = "Invalid stripe count"; | 109 | ti->error = "Invalid stripe count"; |
114 | return -EINVAL; | 110 | return -EINVAL; |
115 | } | 111 | } |
116 | 112 | ||
117 | chunk_size = simple_strtoul(argv[1], &end, 10); | 113 | if (kstrtouint(argv[1], 10, &chunk_size) || !chunk_size) { |
118 | if (*end) { | ||
119 | ti->error = "Invalid chunk_size"; | 114 | ti->error = "Invalid chunk_size"; |
120 | return -EINVAL; | 115 | return -EINVAL; |
121 | } | 116 | } |
122 | 117 | ||
123 | /* | 118 | width = ti->len; |
124 | * chunk_size is a power of two | 119 | if (sector_div(width, chunk_size)) { |
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 " | 120 | ti->error = "Target length not divisible by " |
134 | "chunk size"; | 121 | "chunk size"; |
135 | return -EINVAL; | 122 | return -EINVAL; |
136 | } | 123 | } |
137 | 124 | ||
138 | width = ti->len; | ||
139 | if (sector_div(width, stripes)) { | 125 | if (sector_div(width, stripes)) { |
140 | ti->error = "Target length not divisible by " | 126 | ti->error = "Target length not divisible by " |
141 | "number of stripes"; | 127 | "number of stripes"; |
@@ -167,17 +153,21 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
167 | 153 | ||
168 | if (stripes & (stripes - 1)) | 154 | if (stripes & (stripes - 1)) |
169 | sc->stripes_shift = -1; | 155 | sc->stripes_shift = -1; |
170 | else { | 156 | else |
171 | sc->stripes_shift = ffs(stripes) - 1; | 157 | sc->stripes_shift = __ffs(stripes); |
172 | sc->stripes_mask = ((sector_t) stripes) - 1; | 158 | |
173 | } | 159 | r = dm_set_target_max_io_len(ti, chunk_size); |
160 | if (r) | ||
161 | return r; | ||
174 | 162 | ||
175 | ti->split_io = chunk_size; | ||
176 | ti->num_flush_requests = stripes; | 163 | ti->num_flush_requests = stripes; |
177 | ti->num_discard_requests = stripes; | 164 | ti->num_discard_requests = stripes; |
178 | 165 | ||
179 | sc->chunk_shift = ffs(chunk_size) - 1; | 166 | sc->chunk_size = chunk_size; |
180 | sc->chunk_mask = ((sector_t) chunk_size) - 1; | 167 | if (chunk_size & (chunk_size - 1)) |
168 | sc->chunk_size_shift = -1; | ||
169 | else | ||
170 | sc->chunk_size_shift = __ffs(chunk_size); | ||
181 | 171 | ||
182 | /* | 172 | /* |
183 | * Get the stripe destinations. | 173 | * Get the stripe destinations. |
@@ -216,17 +206,29 @@ static void stripe_dtr(struct dm_target *ti) | |||
216 | static void stripe_map_sector(struct stripe_c *sc, sector_t sector, | 206 | static void stripe_map_sector(struct stripe_c *sc, sector_t sector, |
217 | uint32_t *stripe, sector_t *result) | 207 | uint32_t *stripe, sector_t *result) |
218 | { | 208 | { |
219 | sector_t offset = dm_target_offset(sc->ti, sector); | 209 | sector_t chunk = dm_target_offset(sc->ti, sector); |
220 | sector_t chunk = offset >> sc->chunk_shift; | 210 | sector_t chunk_offset; |
211 | |||
212 | if (sc->chunk_size_shift < 0) | ||
213 | chunk_offset = sector_div(chunk, sc->chunk_size); | ||
214 | else { | ||
215 | chunk_offset = chunk & (sc->chunk_size - 1); | ||
216 | chunk >>= sc->chunk_size_shift; | ||
217 | } | ||
221 | 218 | ||
222 | if (sc->stripes_shift < 0) | 219 | if (sc->stripes_shift < 0) |
223 | *stripe = sector_div(chunk, sc->stripes); | 220 | *stripe = sector_div(chunk, sc->stripes); |
224 | else { | 221 | else { |
225 | *stripe = chunk & sc->stripes_mask; | 222 | *stripe = chunk & (sc->stripes - 1); |
226 | chunk >>= sc->stripes_shift; | 223 | chunk >>= sc->stripes_shift; |
227 | } | 224 | } |
228 | 225 | ||
229 | *result = (chunk << sc->chunk_shift) | (offset & sc->chunk_mask); | 226 | if (sc->chunk_size_shift < 0) |
227 | chunk *= sc->chunk_size; | ||
228 | else | ||
229 | chunk <<= sc->chunk_size_shift; | ||
230 | |||
231 | *result = chunk + chunk_offset; | ||
230 | } | 232 | } |
231 | 233 | ||
232 | static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector, | 234 | static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector, |
@@ -237,9 +239,16 @@ static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector, | |||
237 | stripe_map_sector(sc, sector, &stripe, result); | 239 | stripe_map_sector(sc, sector, &stripe, result); |
238 | if (stripe == target_stripe) | 240 | if (stripe == target_stripe) |
239 | return; | 241 | return; |
240 | *result &= ~sc->chunk_mask; /* round down */ | 242 | |
243 | /* round down */ | ||
244 | sector = *result; | ||
245 | if (sc->chunk_size_shift < 0) | ||
246 | *result -= sector_div(sector, sc->chunk_size); | ||
247 | else | ||
248 | *result = sector & ~(sector_t)(sc->chunk_size - 1); | ||
249 | |||
241 | if (target_stripe < stripe) | 250 | if (target_stripe < stripe) |
242 | *result += sc->chunk_mask + 1; /* next chunk */ | 251 | *result += sc->chunk_size; /* next chunk */ |
243 | } | 252 | } |
244 | 253 | ||
245 | static int stripe_map_discard(struct stripe_c *sc, struct bio *bio, | 254 | static int stripe_map_discard(struct stripe_c *sc, struct bio *bio, |
@@ -302,8 +311,8 @@ static int stripe_map(struct dm_target *ti, struct bio *bio, | |||
302 | * | 311 | * |
303 | */ | 312 | */ |
304 | 313 | ||
305 | static int stripe_status(struct dm_target *ti, | 314 | static int stripe_status(struct dm_target *ti, status_type_t type, |
306 | status_type_t type, char *result, unsigned int maxlen) | 315 | unsigned status_flags, char *result, unsigned maxlen) |
307 | { | 316 | { |
308 | struct stripe_c *sc = (struct stripe_c *) ti->private; | 317 | struct stripe_c *sc = (struct stripe_c *) ti->private; |
309 | char buffer[sc->stripes + 1]; | 318 | char buffer[sc->stripes + 1]; |
@@ -324,7 +333,7 @@ static int stripe_status(struct dm_target *ti, | |||
324 | 333 | ||
325 | case STATUSTYPE_TABLE: | 334 | case STATUSTYPE_TABLE: |
326 | DMEMIT("%d %llu", sc->stripes, | 335 | DMEMIT("%d %llu", sc->stripes, |
327 | (unsigned long long)sc->chunk_mask + 1); | 336 | (unsigned long long)sc->chunk_size); |
328 | for (i = 0; i < sc->stripes; i++) | 337 | for (i = 0; i < sc->stripes; i++) |
329 | DMEMIT(" %s %llu", sc->stripe[i].dev->name, | 338 | DMEMIT(" %s %llu", sc->stripe[i].dev->name, |
330 | (unsigned long long)sc->stripe[i].physical_start); | 339 | (unsigned long long)sc->stripe[i].physical_start); |
@@ -391,7 +400,7 @@ static void stripe_io_hints(struct dm_target *ti, | |||
391 | struct queue_limits *limits) | 400 | struct queue_limits *limits) |
392 | { | 401 | { |
393 | struct stripe_c *sc = ti->private; | 402 | struct stripe_c *sc = ti->private; |
394 | unsigned chunk_size = (sc->chunk_mask + 1) << 9; | 403 | unsigned chunk_size = sc->chunk_size << SECTOR_SHIFT; |
395 | 404 | ||
396 | blk_limits_io_min(limits, chunk_size); | 405 | blk_limits_io_min(limits, chunk_size); |
397 | blk_limits_io_opt(limits, chunk_size * sc->stripes); | 406 | blk_limits_io_opt(limits, chunk_size * sc->stripes); |
@@ -419,7 +428,7 @@ static int stripe_merge(struct dm_target *ti, struct bvec_merge_data *bvm, | |||
419 | 428 | ||
420 | static struct target_type stripe_target = { | 429 | static struct target_type stripe_target = { |
421 | .name = "striped", | 430 | .name = "striped", |
422 | .version = {1, 4, 0}, | 431 | .version = {1, 5, 0}, |
423 | .module = THIS_MODULE, | 432 | .module = THIS_MODULE, |
424 | .ctr = stripe_ctr, | 433 | .ctr = stripe_ctr, |
425 | .dtr = stripe_dtr, | 434 | .dtr = stripe_dtr, |