summaryrefslogtreecommitdiffstats
path: root/drivers/md/dm-stripe.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md/dm-stripe.c')
-rw-r--r--drivers/md/dm-stripe.c87
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 {
26struct stripe_c { 26struct 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 */
96static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) 94static 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)
216static void stripe_map_sector(struct stripe_c *sc, sector_t sector, 206static 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
232static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector, 234static 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
245static int stripe_map_discard(struct stripe_c *sc, struct bio *bio, 254static 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
305static int stripe_status(struct dm_target *ti, 314static 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
420static struct target_type stripe_target = { 429static 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,