diff options
Diffstat (limited to 'drivers/md/dm-mpath.c')
-rw-r--r-- | drivers/md/dm-mpath.c | 28 |
1 files changed, 18 insertions, 10 deletions
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index f1cf8f7449d6..890c0e8ed13e 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c | |||
@@ -101,6 +101,7 @@ struct multipath { | |||
101 | struct dm_mpath_io { | 101 | struct dm_mpath_io { |
102 | struct pgpath *pgpath; | 102 | struct pgpath *pgpath; |
103 | struct dm_bio_details details; | 103 | struct dm_bio_details details; |
104 | size_t nr_bytes; | ||
104 | }; | 105 | }; |
105 | 106 | ||
106 | typedef int (*action_fn) (struct pgpath *pgpath); | 107 | typedef int (*action_fn) (struct pgpath *pgpath); |
@@ -244,11 +245,12 @@ static void __switch_pg(struct multipath *m, struct pgpath *pgpath) | |||
244 | m->pg_init_count = 0; | 245 | m->pg_init_count = 0; |
245 | } | 246 | } |
246 | 247 | ||
247 | static int __choose_path_in_pg(struct multipath *m, struct priority_group *pg) | 248 | static int __choose_path_in_pg(struct multipath *m, struct priority_group *pg, |
249 | size_t nr_bytes) | ||
248 | { | 250 | { |
249 | struct dm_path *path; | 251 | struct dm_path *path; |
250 | 252 | ||
251 | path = pg->ps.type->select_path(&pg->ps, &m->repeat_count); | 253 | path = pg->ps.type->select_path(&pg->ps, &m->repeat_count, nr_bytes); |
252 | if (!path) | 254 | if (!path) |
253 | return -ENXIO; | 255 | return -ENXIO; |
254 | 256 | ||
@@ -260,7 +262,7 @@ static int __choose_path_in_pg(struct multipath *m, struct priority_group *pg) | |||
260 | return 0; | 262 | return 0; |
261 | } | 263 | } |
262 | 264 | ||
263 | static void __choose_pgpath(struct multipath *m) | 265 | static void __choose_pgpath(struct multipath *m, size_t nr_bytes) |
264 | { | 266 | { |
265 | struct priority_group *pg; | 267 | struct priority_group *pg; |
266 | unsigned bypassed = 1; | 268 | unsigned bypassed = 1; |
@@ -272,12 +274,12 @@ static void __choose_pgpath(struct multipath *m) | |||
272 | if (m->next_pg) { | 274 | if (m->next_pg) { |
273 | pg = m->next_pg; | 275 | pg = m->next_pg; |
274 | m->next_pg = NULL; | 276 | m->next_pg = NULL; |
275 | if (!__choose_path_in_pg(m, pg)) | 277 | if (!__choose_path_in_pg(m, pg, nr_bytes)) |
276 | return; | 278 | return; |
277 | } | 279 | } |
278 | 280 | ||
279 | /* Don't change PG until it has no remaining paths */ | 281 | /* Don't change PG until it has no remaining paths */ |
280 | if (m->current_pg && !__choose_path_in_pg(m, m->current_pg)) | 282 | if (m->current_pg && !__choose_path_in_pg(m, m->current_pg, nr_bytes)) |
281 | return; | 283 | return; |
282 | 284 | ||
283 | /* | 285 | /* |
@@ -289,7 +291,7 @@ static void __choose_pgpath(struct multipath *m) | |||
289 | list_for_each_entry(pg, &m->priority_groups, list) { | 291 | list_for_each_entry(pg, &m->priority_groups, list) { |
290 | if (pg->bypassed == bypassed) | 292 | if (pg->bypassed == bypassed) |
291 | continue; | 293 | continue; |
292 | if (!__choose_path_in_pg(m, pg)) | 294 | if (!__choose_path_in_pg(m, pg, nr_bytes)) |
293 | return; | 295 | return; |
294 | } | 296 | } |
295 | } while (bypassed--); | 297 | } while (bypassed--); |
@@ -320,6 +322,7 @@ static int map_io(struct multipath *m, struct bio *bio, | |||
320 | struct dm_mpath_io *mpio, unsigned was_queued) | 322 | struct dm_mpath_io *mpio, unsigned was_queued) |
321 | { | 323 | { |
322 | int r = DM_MAPIO_REMAPPED; | 324 | int r = DM_MAPIO_REMAPPED; |
325 | size_t nr_bytes = bio->bi_size; | ||
323 | unsigned long flags; | 326 | unsigned long flags; |
324 | struct pgpath *pgpath; | 327 | struct pgpath *pgpath; |
325 | 328 | ||
@@ -328,7 +331,7 @@ static int map_io(struct multipath *m, struct bio *bio, | |||
328 | /* Do we need to select a new pgpath? */ | 331 | /* Do we need to select a new pgpath? */ |
329 | if (!m->current_pgpath || | 332 | if (!m->current_pgpath || |
330 | (!m->queue_io && (m->repeat_count && --m->repeat_count == 0))) | 333 | (!m->queue_io && (m->repeat_count && --m->repeat_count == 0))) |
331 | __choose_pgpath(m); | 334 | __choose_pgpath(m, nr_bytes); |
332 | 335 | ||
333 | pgpath = m->current_pgpath; | 336 | pgpath = m->current_pgpath; |
334 | 337 | ||
@@ -353,6 +356,11 @@ static int map_io(struct multipath *m, struct bio *bio, | |||
353 | r = -EIO; /* Failed */ | 356 | r = -EIO; /* Failed */ |
354 | 357 | ||
355 | mpio->pgpath = pgpath; | 358 | mpio->pgpath = pgpath; |
359 | mpio->nr_bytes = nr_bytes; | ||
360 | |||
361 | if (r == DM_MAPIO_REMAPPED && pgpath->pg->ps.type->start_io) | ||
362 | pgpath->pg->ps.type->start_io(&pgpath->pg->ps, &pgpath->path, | ||
363 | nr_bytes); | ||
356 | 364 | ||
357 | spin_unlock_irqrestore(&m->lock, flags); | 365 | spin_unlock_irqrestore(&m->lock, flags); |
358 | 366 | ||
@@ -431,7 +439,7 @@ static void process_queued_ios(struct work_struct *work) | |||
431 | goto out; | 439 | goto out; |
432 | 440 | ||
433 | if (!m->current_pgpath) | 441 | if (!m->current_pgpath) |
434 | __choose_pgpath(m); | 442 | __choose_pgpath(m, 0); |
435 | 443 | ||
436 | pgpath = m->current_pgpath; | 444 | pgpath = m->current_pgpath; |
437 | 445 | ||
@@ -1209,7 +1217,7 @@ static int multipath_end_io(struct dm_target *ti, struct bio *bio, | |||
1209 | if (pgpath) { | 1217 | if (pgpath) { |
1210 | ps = &pgpath->pg->ps; | 1218 | ps = &pgpath->pg->ps; |
1211 | if (ps->type->end_io) | 1219 | if (ps->type->end_io) |
1212 | ps->type->end_io(ps, &pgpath->path); | 1220 | ps->type->end_io(ps, &pgpath->path, mpio->nr_bytes); |
1213 | } | 1221 | } |
1214 | if (r != DM_ENDIO_INCOMPLETE) | 1222 | if (r != DM_ENDIO_INCOMPLETE) |
1215 | mempool_free(mpio, m->mpio_pool); | 1223 | mempool_free(mpio, m->mpio_pool); |
@@ -1425,7 +1433,7 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd, | |||
1425 | spin_lock_irqsave(&m->lock, flags); | 1433 | spin_lock_irqsave(&m->lock, flags); |
1426 | 1434 | ||
1427 | if (!m->current_pgpath) | 1435 | if (!m->current_pgpath) |
1428 | __choose_pgpath(m); | 1436 | __choose_pgpath(m, 0); |
1429 | 1437 | ||
1430 | if (m->current_pgpath) { | 1438 | if (m->current_pgpath) { |
1431 | bdev = m->current_pgpath->path.dev->bdev; | 1439 | bdev = m->current_pgpath->path.dev->bdev; |