diff options
author | Mike Snitzer <snitzer@redhat.com> | 2012-07-27 10:08:01 -0400 |
---|---|---|
committer | Alasdair G Kergon <agk@redhat.com> | 2012-07-27 10:08:01 -0400 |
commit | eb850de608cc22e0199b3797cd5c0076bae6cda0 (patch) | |
tree | 60cf311ac60af6fc5cae3b2cacca19ab8a74e7aa /drivers/md/dm-stripe.c | |
parent | 542f90381422676544382d4071ba44a2de90a0c1 (diff) |
dm stripe: support for non power of 2 chunksize
Support non-power-of-2 chunk sizes with dm striping for proper alignment
of stripe IO on storage that has non-power-of-2 optimal IO sizes (e.g.
RAID6 10+2).
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Diffstat (limited to 'drivers/md/dm-stripe.c')
-rw-r--r-- | drivers/md/dm-stripe.c | 44 |
1 files changed, 19 insertions, 25 deletions
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index 992c9d4c3bd9..9690daa11c83 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c | |||
@@ -30,9 +30,7 @@ struct stripe_c { | |||
30 | /* The size of this target / num. stripes */ | 30 | /* The size of this target / num. stripes */ |
31 | sector_t stripe_width; | 31 | sector_t stripe_width; |
32 | 32 | ||
33 | /* stripe chunk size */ | 33 | uint32_t chunk_size; |
34 | uint32_t chunk_shift; | ||
35 | sector_t chunk_mask; | ||
36 | 34 | ||
37 | /* Needed for handling events */ | 35 | /* Needed for handling events */ |
38 | struct dm_target *ti; | 36 | struct dm_target *ti; |
@@ -90,7 +88,7 @@ static int get_stripe(struct dm_target *ti, struct stripe_c *sc, | |||
90 | 88 | ||
91 | /* | 89 | /* |
92 | * Construct a striped mapping. | 90 | * Construct a striped mapping. |
93 | * <number of stripes> <chunk size (2^^n)> [<dev_path> <offset>]+ | 91 | * <number of stripes> <chunk size> [<dev_path> <offset>]+ |
94 | */ | 92 | */ |
95 | static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) | 93 | static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) |
96 | { | 94 | { |
@@ -111,21 +109,14 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
111 | return -EINVAL; | 109 | return -EINVAL; |
112 | } | 110 | } |
113 | 111 | ||
114 | if (kstrtouint(argv[1], 10, &chunk_size)) { | 112 | if (kstrtouint(argv[1], 10, &chunk_size) || |
115 | ti->error = "Invalid chunk_size"; | ||
116 | return -EINVAL; | ||
117 | } | ||
118 | |||
119 | /* | ||
120 | * chunk_size is a power of two | ||
121 | */ | ||
122 | if (!is_power_of_2(chunk_size) || | ||
123 | (chunk_size < (PAGE_SIZE >> SECTOR_SHIFT))) { | 113 | (chunk_size < (PAGE_SIZE >> SECTOR_SHIFT))) { |
124 | ti->error = "Invalid chunk size"; | 114 | ti->error = "Invalid chunk_size"; |
125 | return -EINVAL; | 115 | return -EINVAL; |
126 | } | 116 | } |
127 | 117 | ||
128 | if (ti->len & (chunk_size - 1)) { | 118 | width = ti->len; |
119 | if (sector_div(width, chunk_size)) { | ||
129 | ti->error = "Target length not divisible by " | 120 | ti->error = "Target length not divisible by " |
130 | "chunk size"; | 121 | "chunk size"; |
131 | return -EINVAL; | 122 | return -EINVAL; |
@@ -172,8 +163,7 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
172 | ti->num_flush_requests = stripes; | 163 | ti->num_flush_requests = stripes; |
173 | ti->num_discard_requests = stripes; | 164 | ti->num_discard_requests = stripes; |
174 | 165 | ||
175 | sc->chunk_shift = ffs(chunk_size) - 1; | 166 | sc->chunk_size = chunk_size; |
176 | sc->chunk_mask = ((sector_t) chunk_size) - 1; | ||
177 | 167 | ||
178 | /* | 168 | /* |
179 | * Get the stripe destinations. | 169 | * Get the stripe destinations. |
@@ -212,8 +202,8 @@ static void stripe_dtr(struct dm_target *ti) | |||
212 | static void stripe_map_sector(struct stripe_c *sc, sector_t sector, | 202 | static void stripe_map_sector(struct stripe_c *sc, sector_t sector, |
213 | uint32_t *stripe, sector_t *result) | 203 | uint32_t *stripe, sector_t *result) |
214 | { | 204 | { |
215 | sector_t offset = dm_target_offset(sc->ti, sector); | 205 | sector_t chunk = dm_target_offset(sc->ti, sector); |
216 | sector_t chunk = offset >> sc->chunk_shift; | 206 | sector_t chunk_offset = sector_div(chunk, sc->chunk_size); |
217 | 207 | ||
218 | if (sc->stripes_shift < 0) | 208 | if (sc->stripes_shift < 0) |
219 | *stripe = sector_div(chunk, sc->stripes); | 209 | *stripe = sector_div(chunk, sc->stripes); |
@@ -222,7 +212,7 @@ static void stripe_map_sector(struct stripe_c *sc, sector_t sector, | |||
222 | chunk >>= sc->stripes_shift; | 212 | chunk >>= sc->stripes_shift; |
223 | } | 213 | } |
224 | 214 | ||
225 | *result = (chunk << sc->chunk_shift) | (offset & sc->chunk_mask); | 215 | *result = (chunk * sc->chunk_size) + chunk_offset; |
226 | } | 216 | } |
227 | 217 | ||
228 | static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector, | 218 | static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector, |
@@ -233,9 +223,13 @@ static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector, | |||
233 | stripe_map_sector(sc, sector, &stripe, result); | 223 | stripe_map_sector(sc, sector, &stripe, result); |
234 | if (stripe == target_stripe) | 224 | if (stripe == target_stripe) |
235 | return; | 225 | return; |
236 | *result &= ~sc->chunk_mask; /* round down */ | 226 | |
227 | /* round down */ | ||
228 | sector = *result; | ||
229 | *result -= sector_div(sector, sc->chunk_size); | ||
230 | |||
237 | if (target_stripe < stripe) | 231 | if (target_stripe < stripe) |
238 | *result += sc->chunk_mask + 1; /* next chunk */ | 232 | *result += sc->chunk_size; /* next chunk */ |
239 | } | 233 | } |
240 | 234 | ||
241 | static int stripe_map_discard(struct stripe_c *sc, struct bio *bio, | 235 | static int stripe_map_discard(struct stripe_c *sc, struct bio *bio, |
@@ -320,7 +314,7 @@ static int stripe_status(struct dm_target *ti, | |||
320 | 314 | ||
321 | case STATUSTYPE_TABLE: | 315 | case STATUSTYPE_TABLE: |
322 | DMEMIT("%d %llu", sc->stripes, | 316 | DMEMIT("%d %llu", sc->stripes, |
323 | (unsigned long long)sc->chunk_mask + 1); | 317 | (unsigned long long)sc->chunk_size); |
324 | for (i = 0; i < sc->stripes; i++) | 318 | for (i = 0; i < sc->stripes; i++) |
325 | DMEMIT(" %s %llu", sc->stripe[i].dev->name, | 319 | DMEMIT(" %s %llu", sc->stripe[i].dev->name, |
326 | (unsigned long long)sc->stripe[i].physical_start); | 320 | (unsigned long long)sc->stripe[i].physical_start); |
@@ -387,7 +381,7 @@ static void stripe_io_hints(struct dm_target *ti, | |||
387 | struct queue_limits *limits) | 381 | struct queue_limits *limits) |
388 | { | 382 | { |
389 | struct stripe_c *sc = ti->private; | 383 | struct stripe_c *sc = ti->private; |
390 | unsigned chunk_size = (sc->chunk_mask + 1) << 9; | 384 | unsigned chunk_size = sc->chunk_size << SECTOR_SHIFT; |
391 | 385 | ||
392 | blk_limits_io_min(limits, chunk_size); | 386 | blk_limits_io_min(limits, chunk_size); |
393 | blk_limits_io_opt(limits, chunk_size * sc->stripes); | 387 | blk_limits_io_opt(limits, chunk_size * sc->stripes); |
@@ -415,7 +409,7 @@ static int stripe_merge(struct dm_target *ti, struct bvec_merge_data *bvm, | |||
415 | 409 | ||
416 | static struct target_type stripe_target = { | 410 | static struct target_type stripe_target = { |
417 | .name = "striped", | 411 | .name = "striped", |
418 | .version = {1, 4, 0}, | 412 | .version = {1, 5, 0}, |
419 | .module = THIS_MODULE, | 413 | .module = THIS_MODULE, |
420 | .ctr = stripe_ctr, | 414 | .ctr = stripe_ctr, |
421 | .dtr = stripe_dtr, | 415 | .dtr = stripe_dtr, |