aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/dm-stripe.c
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-17 16:15:55 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-17 16:15:55 -0500
commit8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch)
treea8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /drivers/md/dm-stripe.c
parent406089d01562f1e2bf9f089fd7637009ebaad589 (diff)
Patched in Tegra support.
Diffstat (limited to 'drivers/md/dm-stripe.c')
-rw-r--r--drivers/md/dm-stripe.c112
1 files changed, 51 insertions, 61 deletions
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c
index c89cde86d40..3d80cf0c152 100644
--- a/drivers/md/dm-stripe.c
+++ b/drivers/md/dm-stripe.c
@@ -26,12 +26,14 @@ 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;
29 30
30 /* The size of this target / num. stripes */ 31 /* The size of this target / num. stripes */
31 sector_t stripe_width; 32 sector_t stripe_width;
32 33
33 uint32_t chunk_size; 34 /* stripe chunk size */
34 int chunk_size_shift; 35 uint32_t chunk_shift;
36 sector_t chunk_mask;
35 37
36 /* Needed for handling events */ 38 /* Needed for handling events */
37 struct dm_target *ti; 39 struct dm_target *ti;
@@ -73,9 +75,8 @@ static int get_stripe(struct dm_target *ti, struct stripe_c *sc,
73 unsigned int stripe, char **argv) 75 unsigned int stripe, char **argv)
74{ 76{
75 unsigned long long start; 77 unsigned long long start;
76 char dummy;
77 78
78 if (sscanf(argv[1], "%llu%c", &start, &dummy) != 1) 79 if (sscanf(argv[1], "%llu", &start) != 1)
79 return -EINVAL; 80 return -EINVAL;
80 81
81 if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), 82 if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table),
@@ -89,7 +90,7 @@ static int get_stripe(struct dm_target *ti, struct stripe_c *sc,
89 90
90/* 91/*
91 * Construct a striped mapping. 92 * Construct a striped mapping.
92 * <number of stripes> <chunk size> [<dev_path> <offset>]+ 93 * <number of stripes> <chunk size (2^^n)> [<dev_path> <offset>]+
93 */ 94 */
94static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) 95static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
95{ 96{
@@ -97,6 +98,7 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
97 sector_t width; 98 sector_t width;
98 uint32_t stripes; 99 uint32_t stripes;
99 uint32_t chunk_size; 100 uint32_t chunk_size;
101 char *end;
100 int r; 102 int r;
101 unsigned int i; 103 unsigned int i;
102 104
@@ -105,23 +107,34 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
105 return -EINVAL; 107 return -EINVAL;
106 } 108 }
107 109
108 if (kstrtouint(argv[0], 10, &stripes) || !stripes) { 110 stripes = simple_strtoul(argv[0], &end, 10);
111 if (!stripes || *end) {
109 ti->error = "Invalid stripe count"; 112 ti->error = "Invalid stripe count";
110 return -EINVAL; 113 return -EINVAL;
111 } 114 }
112 115
113 if (kstrtouint(argv[1], 10, &chunk_size) || !chunk_size) { 116 chunk_size = simple_strtoul(argv[1], &end, 10);
117 if (*end) {
114 ti->error = "Invalid chunk_size"; 118 ti->error = "Invalid chunk_size";
115 return -EINVAL; 119 return -EINVAL;
116 } 120 }
117 121
118 width = ti->len; 122 /*
119 if (sector_div(width, chunk_size)) { 123 * chunk_size is a power of two
124 */
125 if (!is_power_of_2(chunk_size) ||
126 (chunk_size < (PAGE_SIZE >> SECTOR_SHIFT))) {
127 ti->error = "Invalid chunk size";
128 return -EINVAL;
129 }
130
131 if (ti->len & (chunk_size - 1)) {
120 ti->error = "Target length not divisible by " 132 ti->error = "Target length not divisible by "
121 "chunk size"; 133 "chunk size";
122 return -EINVAL; 134 return -EINVAL;
123 } 135 }
124 136
137 width = ti->len;
125 if (sector_div(width, stripes)) { 138 if (sector_div(width, stripes)) {
126 ti->error = "Target length not divisible by " 139 ti->error = "Target length not divisible by "
127 "number of stripes"; 140 "number of stripes";
@@ -153,22 +166,17 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
153 166
154 if (stripes & (stripes - 1)) 167 if (stripes & (stripes - 1))
155 sc->stripes_shift = -1; 168 sc->stripes_shift = -1;
156 else 169 else {
157 sc->stripes_shift = __ffs(stripes); 170 sc->stripes_shift = ffs(stripes) - 1;
158 171 sc->stripes_mask = ((sector_t) stripes) - 1;
159 r = dm_set_target_max_io_len(ti, chunk_size); 172 }
160 if (r)
161 return r;
162 173
174 ti->split_io = chunk_size;
163 ti->num_flush_requests = stripes; 175 ti->num_flush_requests = stripes;
164 ti->num_discard_requests = stripes; 176 ti->num_discard_requests = stripes;
165 ti->num_write_same_requests = stripes;
166 177
167 sc->chunk_size = chunk_size; 178 sc->chunk_shift = ffs(chunk_size) - 1;
168 if (chunk_size & (chunk_size - 1)) 179 sc->chunk_mask = ((sector_t) chunk_size) - 1;
169 sc->chunk_size_shift = -1;
170 else
171 sc->chunk_size_shift = __ffs(chunk_size);
172 180
173 /* 181 /*
174 * Get the stripe destinations. 182 * Get the stripe destinations.
@@ -200,36 +208,24 @@ static void stripe_dtr(struct dm_target *ti)
200 for (i = 0; i < sc->stripes; i++) 208 for (i = 0; i < sc->stripes; i++)
201 dm_put_device(ti, sc->stripe[i].dev); 209 dm_put_device(ti, sc->stripe[i].dev);
202 210
203 flush_work(&sc->trigger_event); 211 flush_work_sync(&sc->trigger_event);
204 kfree(sc); 212 kfree(sc);
205} 213}
206 214
207static void stripe_map_sector(struct stripe_c *sc, sector_t sector, 215static void stripe_map_sector(struct stripe_c *sc, sector_t sector,
208 uint32_t *stripe, sector_t *result) 216 uint32_t *stripe, sector_t *result)
209{ 217{
210 sector_t chunk = dm_target_offset(sc->ti, sector); 218 sector_t offset = dm_target_offset(sc->ti, sector);
211 sector_t chunk_offset; 219 sector_t chunk = offset >> sc->chunk_shift;
212
213 if (sc->chunk_size_shift < 0)
214 chunk_offset = sector_div(chunk, sc->chunk_size);
215 else {
216 chunk_offset = chunk & (sc->chunk_size - 1);
217 chunk >>= sc->chunk_size_shift;
218 }
219 220
220 if (sc->stripes_shift < 0) 221 if (sc->stripes_shift < 0)
221 *stripe = sector_div(chunk, sc->stripes); 222 *stripe = sector_div(chunk, sc->stripes);
222 else { 223 else {
223 *stripe = chunk & (sc->stripes - 1); 224 *stripe = chunk & sc->stripes_mask;
224 chunk >>= sc->stripes_shift; 225 chunk >>= sc->stripes_shift;
225 } 226 }
226 227
227 if (sc->chunk_size_shift < 0) 228 *result = (chunk << sc->chunk_shift) | (offset & sc->chunk_mask);
228 chunk *= sc->chunk_size;
229 else
230 chunk <<= sc->chunk_size_shift;
231
232 *result = chunk + chunk_offset;
233} 229}
234 230
235static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector, 231static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector,
@@ -240,20 +236,13 @@ static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector,
240 stripe_map_sector(sc, sector, &stripe, result); 236 stripe_map_sector(sc, sector, &stripe, result);
241 if (stripe == target_stripe) 237 if (stripe == target_stripe)
242 return; 238 return;
243 239 *result &= ~sc->chunk_mask; /* round down */
244 /* round down */
245 sector = *result;
246 if (sc->chunk_size_shift < 0)
247 *result -= sector_div(sector, sc->chunk_size);
248 else
249 *result = sector & ~(sector_t)(sc->chunk_size - 1);
250
251 if (target_stripe < stripe) 240 if (target_stripe < stripe)
252 *result += sc->chunk_size; /* next chunk */ 241 *result += sc->chunk_mask + 1; /* next chunk */
253} 242}
254 243
255static int stripe_map_range(struct stripe_c *sc, struct bio *bio, 244static int stripe_map_discard(struct stripe_c *sc, struct bio *bio,
256 uint32_t target_stripe) 245 uint32_t target_stripe)
257{ 246{
258 sector_t begin, end; 247 sector_t begin, end;
259 248
@@ -272,23 +261,23 @@ static int stripe_map_range(struct stripe_c *sc, struct bio *bio,
272 } 261 }
273} 262}
274 263
275static int stripe_map(struct dm_target *ti, struct bio *bio) 264static int stripe_map(struct dm_target *ti, struct bio *bio,
265 union map_info *map_context)
276{ 266{
277 struct stripe_c *sc = ti->private; 267 struct stripe_c *sc = ti->private;
278 uint32_t stripe; 268 uint32_t stripe;
279 unsigned target_request_nr; 269 unsigned target_request_nr;
280 270
281 if (bio->bi_rw & REQ_FLUSH) { 271 if (bio->bi_rw & REQ_FLUSH) {
282 target_request_nr = dm_bio_get_target_request_nr(bio); 272 target_request_nr = map_context->target_request_nr;
283 BUG_ON(target_request_nr >= sc->stripes); 273 BUG_ON(target_request_nr >= sc->stripes);
284 bio->bi_bdev = sc->stripe[target_request_nr].dev->bdev; 274 bio->bi_bdev = sc->stripe[target_request_nr].dev->bdev;
285 return DM_MAPIO_REMAPPED; 275 return DM_MAPIO_REMAPPED;
286 } 276 }
287 if (unlikely(bio->bi_rw & REQ_DISCARD) || 277 if (unlikely(bio->bi_rw & REQ_DISCARD)) {
288 unlikely(bio->bi_rw & REQ_WRITE_SAME)) { 278 target_request_nr = map_context->target_request_nr;
289 target_request_nr = dm_bio_get_target_request_nr(bio);
290 BUG_ON(target_request_nr >= sc->stripes); 279 BUG_ON(target_request_nr >= sc->stripes);
291 return stripe_map_range(sc, bio, target_request_nr); 280 return stripe_map_discard(sc, bio, target_request_nr);
292 } 281 }
293 282
294 stripe_map_sector(sc, bio->bi_sector, &stripe, &bio->bi_sector); 283 stripe_map_sector(sc, bio->bi_sector, &stripe, &bio->bi_sector);
@@ -312,8 +301,8 @@ static int stripe_map(struct dm_target *ti, struct bio *bio)
312 * 301 *
313 */ 302 */
314 303
315static int stripe_status(struct dm_target *ti, status_type_t type, 304static int stripe_status(struct dm_target *ti,
316 unsigned status_flags, char *result, unsigned maxlen) 305 status_type_t type, char *result, unsigned int maxlen)
317{ 306{
318 struct stripe_c *sc = (struct stripe_c *) ti->private; 307 struct stripe_c *sc = (struct stripe_c *) ti->private;
319 char buffer[sc->stripes + 1]; 308 char buffer[sc->stripes + 1];
@@ -334,7 +323,7 @@ static int stripe_status(struct dm_target *ti, status_type_t type,
334 323
335 case STATUSTYPE_TABLE: 324 case STATUSTYPE_TABLE:
336 DMEMIT("%d %llu", sc->stripes, 325 DMEMIT("%d %llu", sc->stripes,
337 (unsigned long long)sc->chunk_size); 326 (unsigned long long)sc->chunk_mask + 1);
338 for (i = 0; i < sc->stripes; i++) 327 for (i = 0; i < sc->stripes; i++)
339 DMEMIT(" %s %llu", sc->stripe[i].dev->name, 328 DMEMIT(" %s %llu", sc->stripe[i].dev->name,
340 (unsigned long long)sc->stripe[i].physical_start); 329 (unsigned long long)sc->stripe[i].physical_start);
@@ -343,7 +332,8 @@ static int stripe_status(struct dm_target *ti, status_type_t type,
343 return 0; 332 return 0;
344} 333}
345 334
346static int stripe_end_io(struct dm_target *ti, struct bio *bio, int error) 335static int stripe_end_io(struct dm_target *ti, struct bio *bio,
336 int error, union map_info *map_context)
347{ 337{
348 unsigned i; 338 unsigned i;
349 char major_minor[16]; 339 char major_minor[16];
@@ -400,7 +390,7 @@ static void stripe_io_hints(struct dm_target *ti,
400 struct queue_limits *limits) 390 struct queue_limits *limits)
401{ 391{
402 struct stripe_c *sc = ti->private; 392 struct stripe_c *sc = ti->private;
403 unsigned chunk_size = sc->chunk_size << SECTOR_SHIFT; 393 unsigned chunk_size = (sc->chunk_mask + 1) << 9;
404 394
405 blk_limits_io_min(limits, chunk_size); 395 blk_limits_io_min(limits, chunk_size);
406 blk_limits_io_opt(limits, chunk_size * sc->stripes); 396 blk_limits_io_opt(limits, chunk_size * sc->stripes);
@@ -428,7 +418,7 @@ static int stripe_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
428 418
429static struct target_type stripe_target = { 419static struct target_type stripe_target = {
430 .name = "striped", 420 .name = "striped",
431 .version = {1, 5, 0}, 421 .version = {1, 4, 0},
432 .module = THIS_MODULE, 422 .module = THIS_MODULE,
433 .ctr = stripe_ctr, 423 .ctr = stripe_ctr,
434 .dtr = stripe_dtr, 424 .dtr = stripe_dtr,