Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Mike Snitzer and committed by
Alasdair G Kergon
eb850de6 542f9038

+21 -27
+2 -2
Documentation/device-mapper/striped.txt
··· 9 9 10 10 Parameters: <num devs> <chunk size> [<dev path> <offset>]+ 11 11 <num devs>: Number of underlying devices. 12 - <chunk size>: Size of each chunk of data. Must be a power-of-2 and at 13 - least as large as the system's PAGE_SIZE. 12 + <chunk size>: Size of each chunk of data. Must be at least as 13 + large as the system's PAGE_SIZE. 14 14 <dev path>: Full pathname to the underlying block-device, or a 15 15 "major:minor" device-number. 16 16 <offset>: Starting sector within the device.
+19 -25
drivers/md/dm-stripe.c
··· 30 30 /* The size of this target / num. stripes */ 31 31 sector_t stripe_width; 32 32 33 - /* stripe chunk size */ 34 - uint32_t chunk_shift; 35 - sector_t chunk_mask; 33 + uint32_t chunk_size; 36 34 37 35 /* Needed for handling events */ 38 36 struct dm_target *ti; ··· 88 90 89 91 /* 90 92 * Construct a striped mapping. 91 - * <number of stripes> <chunk size (2^^n)> [<dev_path> <offset>]+ 93 + * <number of stripes> <chunk size> [<dev_path> <offset>]+ 92 94 */ 93 95 static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) 94 96 { ··· 109 111 return -EINVAL; 110 112 } 111 113 112 - if (kstrtouint(argv[1], 10, &chunk_size)) { 114 + if (kstrtouint(argv[1], 10, &chunk_size) || 115 + (chunk_size < (PAGE_SIZE >> SECTOR_SHIFT))) { 113 116 ti->error = "Invalid chunk_size"; 114 117 return -EINVAL; 115 118 } 116 119 117 - /* 118 - * chunk_size is a power of two 119 - */ 120 - if (!is_power_of_2(chunk_size) || 121 - (chunk_size < (PAGE_SIZE >> SECTOR_SHIFT))) { 122 - ti->error = "Invalid chunk size"; 123 - return -EINVAL; 124 - } 125 - 126 - if (ti->len & (chunk_size - 1)) { 120 + width = ti->len; 121 + if (sector_div(width, chunk_size)) { 127 122 ti->error = "Target length not divisible by " 128 123 "chunk size"; 129 124 return -EINVAL; ··· 163 172 ti->num_flush_requests = stripes; 164 173 ti->num_discard_requests = stripes; 165 174 166 - sc->chunk_shift = ffs(chunk_size) - 1; 167 - sc->chunk_mask = ((sector_t) chunk_size) - 1; 175 + sc->chunk_size = chunk_size; 168 176 169 177 /* 170 178 * Get the stripe destinations. ··· 202 212 static void stripe_map_sector(struct stripe_c *sc, sector_t sector, 203 213 uint32_t *stripe, sector_t *result) 204 214 { 205 - sector_t offset = dm_target_offset(sc->ti, sector); 206 - sector_t chunk = offset >> sc->chunk_shift; 215 + sector_t chunk = dm_target_offset(sc->ti, sector); 216 + sector_t chunk_offset = sector_div(chunk, sc->chunk_size); 207 217 208 218 if (sc->stripes_shift < 0) 209 219 *stripe = sector_div(chunk, sc->stripes); ··· 212 222 chunk >>= sc->stripes_shift; 213 223 } 214 224 215 - *result = (chunk << sc->chunk_shift) | (offset & sc->chunk_mask); 225 + *result = (chunk * sc->chunk_size) + chunk_offset; 216 226 } 217 227 218 228 static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector, ··· 223 233 stripe_map_sector(sc, sector, &stripe, result); 224 234 if (stripe == target_stripe) 225 235 return; 226 - *result &= ~sc->chunk_mask; /* round down */ 236 + 237 + /* round down */ 238 + sector = *result; 239 + *result -= sector_div(sector, sc->chunk_size); 240 + 227 241 if (target_stripe < stripe) 228 - *result += sc->chunk_mask + 1; /* next chunk */ 242 + *result += sc->chunk_size; /* next chunk */ 229 243 } 230 244 231 245 static int stripe_map_discard(struct stripe_c *sc, struct bio *bio, ··· 314 320 315 321 case STATUSTYPE_TABLE: 316 322 DMEMIT("%d %llu", sc->stripes, 317 - (unsigned long long)sc->chunk_mask + 1); 323 + (unsigned long long)sc->chunk_size); 318 324 for (i = 0; i < sc->stripes; i++) 319 325 DMEMIT(" %s %llu", sc->stripe[i].dev->name, 320 326 (unsigned long long)sc->stripe[i].physical_start); ··· 381 387 struct queue_limits *limits) 382 388 { 383 389 struct stripe_c *sc = ti->private; 384 - unsigned chunk_size = (sc->chunk_mask + 1) << 9; 390 + unsigned chunk_size = sc->chunk_size << SECTOR_SHIFT; 385 391 386 392 blk_limits_io_min(limits, chunk_size); 387 393 blk_limits_io_opt(limits, chunk_size * sc->stripes); ··· 409 415 410 416 static struct target_type stripe_target = { 411 417 .name = "striped", 412 - .version = {1, 4, 0}, 418 + .version = {1, 5, 0}, 413 419 .module = THIS_MODULE, 414 420 .ctr = stripe_ctr, 415 421 .dtr = stripe_dtr,