diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /drivers/md/dm-stripe.c | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'drivers/md/dm-stripe.c')
-rw-r--r-- | drivers/md/dm-stripe.c | 112 |
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 { | |||
26 | struct stripe_c { | 26 | struct 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 | */ |
94 | static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) | 95 | static 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 | ||
207 | static void stripe_map_sector(struct stripe_c *sc, sector_t sector, | 215 | static 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 | ||
235 | static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector, | 231 | static 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 | ||
255 | static int stripe_map_range(struct stripe_c *sc, struct bio *bio, | 244 | static 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 | ||
275 | static int stripe_map(struct dm_target *ti, struct bio *bio) | 264 | static 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 | ||
315 | static int stripe_status(struct dm_target *ti, status_type_t type, | 304 | static 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 | ||
346 | static int stripe_end_io(struct dm_target *ti, struct bio *bio, int error) | 335 | static 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 | ||
429 | static struct target_type stripe_target = { | 419 | static 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, |