aboutsummaryrefslogtreecommitdiffstats
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, 74 insertions, 13 deletions
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c
index d6e28d732b4d..c297f6da91ea 100644
--- a/drivers/md/dm-stripe.c
+++ b/drivers/md/dm-stripe.c
@@ -25,6 +25,8 @@ struct stripe {
25 25
26struct stripe_c { 26struct stripe_c {
27 uint32_t stripes; 27 uint32_t stripes;
28 int stripes_shift;
29 sector_t stripes_mask;
28 30
29 /* The size of this target / num. stripes */ 31 /* The size of this target / num. stripes */
30 sector_t stripe_width; 32 sector_t stripe_width;
@@ -162,16 +164,22 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
162 164
163 /* Set pointer to dm target; used in trigger_event */ 165 /* Set pointer to dm target; used in trigger_event */
164 sc->ti = ti; 166 sc->ti = ti;
165
166 sc->stripes = stripes; 167 sc->stripes = stripes;
167 sc->stripe_width = width; 168 sc->stripe_width = width;
169
170 if (stripes & (stripes - 1))
171 sc->stripes_shift = -1;
172 else {
173 sc->stripes_shift = ffs(stripes) - 1;
174 sc->stripes_mask = ((sector_t) stripes) - 1;
175 }
176
168 ti->split_io = chunk_size; 177 ti->split_io = chunk_size;
169 ti->num_flush_requests = stripes; 178 ti->num_flush_requests = stripes;
179 ti->num_discard_requests = stripes;
170 180
181 sc->chunk_shift = ffs(chunk_size) - 1;
171 sc->chunk_mask = ((sector_t) chunk_size) - 1; 182 sc->chunk_mask = ((sector_t) chunk_size) - 1;
172 for (sc->chunk_shift = 0; chunk_size; sc->chunk_shift++)
173 chunk_size >>= 1;
174 sc->chunk_shift--;
175 183
176 /* 184 /*
177 * Get the stripe destinations. 185 * Get the stripe destinations.
@@ -207,26 +215,79 @@ static void stripe_dtr(struct dm_target *ti)
207 kfree(sc); 215 kfree(sc);
208} 216}
209 217
218static void stripe_map_sector(struct stripe_c *sc, sector_t sector,
219 uint32_t *stripe, sector_t *result)
220{
221 sector_t offset = dm_target_offset(sc->ti, sector);
222 sector_t chunk = offset >> sc->chunk_shift;
223
224 if (sc->stripes_shift < 0)
225 *stripe = sector_div(chunk, sc->stripes);
226 else {
227 *stripe = chunk & sc->stripes_mask;
228 chunk >>= sc->stripes_shift;
229 }
230
231 *result = (chunk << sc->chunk_shift) | (offset & sc->chunk_mask);
232}
233
234static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector,
235 uint32_t target_stripe, sector_t *result)
236{
237 uint32_t stripe;
238
239 stripe_map_sector(sc, sector, &stripe, result);
240 if (stripe == target_stripe)
241 return;
242 *result &= ~sc->chunk_mask; /* round down */
243 if (target_stripe < stripe)
244 *result += sc->chunk_mask + 1; /* next chunk */
245}
246
247static int stripe_map_discard(struct stripe_c *sc, struct bio *bio,
248 uint32_t target_stripe)
249{
250 sector_t begin, end;
251
252 stripe_map_range_sector(sc, bio->bi_sector, target_stripe, &begin);
253 stripe_map_range_sector(sc, bio->bi_sector + bio_sectors(bio),
254 target_stripe, &end);
255 if (begin < end) {
256 bio->bi_bdev = sc->stripe[target_stripe].dev->bdev;
257 bio->bi_sector = begin + sc->stripe[target_stripe].physical_start;
258 bio->bi_size = to_bytes(end - begin);
259 return DM_MAPIO_REMAPPED;
260 } else {
261 /* The range doesn't map to the target stripe */
262 bio_endio(bio, 0);
263 return DM_MAPIO_SUBMITTED;
264 }
265}
266
210static int stripe_map(struct dm_target *ti, struct bio *bio, 267static int stripe_map(struct dm_target *ti, struct bio *bio,
211 union map_info *map_context) 268 union map_info *map_context)
212{ 269{
213 struct stripe_c *sc = (struct stripe_c *) ti->private; 270 struct stripe_c *sc = ti->private;
214 sector_t offset, chunk;
215 uint32_t stripe; 271 uint32_t stripe;
272 unsigned target_request_nr;
216 273
217 if (unlikely(bio_empty_barrier(bio))) { 274 if (unlikely(bio_empty_barrier(bio))) {
218 BUG_ON(map_context->flush_request >= sc->stripes); 275 target_request_nr = map_context->target_request_nr;
219 bio->bi_bdev = sc->stripe[map_context->flush_request].dev->bdev; 276 BUG_ON(target_request_nr >= sc->stripes);
277 bio->bi_bdev = sc->stripe[target_request_nr].dev->bdev;
220 return DM_MAPIO_REMAPPED; 278 return DM_MAPIO_REMAPPED;
221 } 279 }
280 if (unlikely(bio->bi_rw & REQ_DISCARD)) {
281 target_request_nr = map_context->target_request_nr;
282 BUG_ON(target_request_nr >= sc->stripes);
283 return stripe_map_discard(sc, bio, target_request_nr);
284 }
222 285
223 offset = bio->bi_sector - ti->begin; 286 stripe_map_sector(sc, bio->bi_sector, &stripe, &bio->bi_sector);
224 chunk = offset >> sc->chunk_shift;
225 stripe = sector_div(chunk, sc->stripes);
226 287
288 bio->bi_sector += sc->stripe[stripe].physical_start;
227 bio->bi_bdev = sc->stripe[stripe].dev->bdev; 289 bio->bi_bdev = sc->stripe[stripe].dev->bdev;
228 bio->bi_sector = sc->stripe[stripe].physical_start + 290
229 (chunk << sc->chunk_shift) + (offset & sc->chunk_mask);
230 return DM_MAPIO_REMAPPED; 291 return DM_MAPIO_REMAPPED;
231} 292}
232 293