diff options
Diffstat (limited to 'drivers/md/dm-mpath.c')
-rw-r--r-- | drivers/md/dm-mpath.c | 47 |
1 files changed, 30 insertions, 17 deletions
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 754f38f8a692..638dae048b4f 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/time.h> | 19 | #include <linux/time.h> |
20 | #include <linux/workqueue.h> | 20 | #include <linux/workqueue.h> |
21 | #include <linux/delay.h> | ||
21 | #include <scsi/scsi_dh.h> | 22 | #include <scsi/scsi_dh.h> |
22 | #include <linux/atomic.h> | 23 | #include <linux/atomic.h> |
23 | 24 | ||
@@ -61,11 +62,11 @@ struct multipath { | |||
61 | struct list_head list; | 62 | struct list_head list; |
62 | struct dm_target *ti; | 63 | struct dm_target *ti; |
63 | 64 | ||
64 | spinlock_t lock; | ||
65 | |||
66 | const char *hw_handler_name; | 65 | const char *hw_handler_name; |
67 | char *hw_handler_params; | 66 | char *hw_handler_params; |
68 | 67 | ||
68 | spinlock_t lock; | ||
69 | |||
69 | unsigned nr_priority_groups; | 70 | unsigned nr_priority_groups; |
70 | struct list_head priority_groups; | 71 | struct list_head priority_groups; |
71 | 72 | ||
@@ -81,16 +82,17 @@ struct multipath { | |||
81 | struct priority_group *next_pg; /* Switch to this PG if set */ | 82 | struct priority_group *next_pg; /* Switch to this PG if set */ |
82 | unsigned repeat_count; /* I/Os left before calling PS again */ | 83 | unsigned repeat_count; /* I/Os left before calling PS again */ |
83 | 84 | ||
84 | unsigned queue_io; /* Must we queue all I/O? */ | 85 | unsigned queue_io:1; /* Must we queue all I/O? */ |
85 | unsigned queue_if_no_path; /* Queue I/O if last path fails? */ | 86 | unsigned queue_if_no_path:1; /* Queue I/O if last path fails? */ |
86 | unsigned saved_queue_if_no_path;/* Saved state during suspension */ | 87 | unsigned saved_queue_if_no_path:1; /* Saved state during suspension */ |
88 | |||
87 | unsigned pg_init_retries; /* Number of times to retry pg_init */ | 89 | unsigned pg_init_retries; /* Number of times to retry pg_init */ |
88 | unsigned pg_init_count; /* Number of times pg_init called */ | 90 | unsigned pg_init_count; /* Number of times pg_init called */ |
89 | unsigned pg_init_delay_msecs; /* Number of msecs before pg_init retry */ | 91 | unsigned pg_init_delay_msecs; /* Number of msecs before pg_init retry */ |
90 | 92 | ||
93 | unsigned queue_size; | ||
91 | struct work_struct process_queued_ios; | 94 | struct work_struct process_queued_ios; |
92 | struct list_head queued_ios; | 95 | struct list_head queued_ios; |
93 | unsigned queue_size; | ||
94 | 96 | ||
95 | struct work_struct trigger_event; | 97 | struct work_struct trigger_event; |
96 | 98 | ||
@@ -328,14 +330,18 @@ static void __choose_pgpath(struct multipath *m, size_t nr_bytes) | |||
328 | /* | 330 | /* |
329 | * Loop through priority groups until we find a valid path. | 331 | * Loop through priority groups until we find a valid path. |
330 | * First time we skip PGs marked 'bypassed'. | 332 | * First time we skip PGs marked 'bypassed'. |
331 | * Second time we only try the ones we skipped. | 333 | * Second time we only try the ones we skipped, but set |
334 | * pg_init_delay_retry so we do not hammer controllers. | ||
332 | */ | 335 | */ |
333 | do { | 336 | do { |
334 | list_for_each_entry(pg, &m->priority_groups, list) { | 337 | list_for_each_entry(pg, &m->priority_groups, list) { |
335 | if (pg->bypassed == bypassed) | 338 | if (pg->bypassed == bypassed) |
336 | continue; | 339 | continue; |
337 | if (!__choose_path_in_pg(m, pg, nr_bytes)) | 340 | if (!__choose_path_in_pg(m, pg, nr_bytes)) { |
341 | if (!bypassed) | ||
342 | m->pg_init_delay_retry = 1; | ||
338 | return; | 343 | return; |
344 | } | ||
339 | } | 345 | } |
340 | } while (bypassed--); | 346 | } while (bypassed--); |
341 | 347 | ||
@@ -481,9 +487,6 @@ static void process_queued_ios(struct work_struct *work) | |||
481 | 487 | ||
482 | spin_lock_irqsave(&m->lock, flags); | 488 | spin_lock_irqsave(&m->lock, flags); |
483 | 489 | ||
484 | if (!m->queue_size) | ||
485 | goto out; | ||
486 | |||
487 | if (!m->current_pgpath) | 490 | if (!m->current_pgpath) |
488 | __choose_pgpath(m, 0); | 491 | __choose_pgpath(m, 0); |
489 | 492 | ||
@@ -496,7 +499,6 @@ static void process_queued_ios(struct work_struct *work) | |||
496 | if (m->pg_init_required && !m->pg_init_in_progress && pgpath) | 499 | if (m->pg_init_required && !m->pg_init_in_progress && pgpath) |
497 | __pg_init_all_paths(m); | 500 | __pg_init_all_paths(m); |
498 | 501 | ||
499 | out: | ||
500 | spin_unlock_irqrestore(&m->lock, flags); | 502 | spin_unlock_irqrestore(&m->lock, flags); |
501 | if (!must_queue) | 503 | if (!must_queue) |
502 | dispatch_queued_ios(m); | 504 | dispatch_queued_ios(m); |
@@ -1517,11 +1519,16 @@ out: | |||
1517 | static int multipath_ioctl(struct dm_target *ti, unsigned int cmd, | 1519 | static int multipath_ioctl(struct dm_target *ti, unsigned int cmd, |
1518 | unsigned long arg) | 1520 | unsigned long arg) |
1519 | { | 1521 | { |
1520 | struct multipath *m = (struct multipath *) ti->private; | 1522 | struct multipath *m = ti->private; |
1521 | struct block_device *bdev = NULL; | 1523 | struct block_device *bdev; |
1522 | fmode_t mode = 0; | 1524 | fmode_t mode; |
1523 | unsigned long flags; | 1525 | unsigned long flags; |
1524 | int r = 0; | 1526 | int r; |
1527 | |||
1528 | again: | ||
1529 | bdev = NULL; | ||
1530 | mode = 0; | ||
1531 | r = 0; | ||
1525 | 1532 | ||
1526 | spin_lock_irqsave(&m->lock, flags); | 1533 | spin_lock_irqsave(&m->lock, flags); |
1527 | 1534 | ||
@@ -1546,6 +1553,12 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd, | |||
1546 | if (!r && ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT) | 1553 | if (!r && ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT) |
1547 | r = scsi_verify_blk_ioctl(NULL, cmd); | 1554 | r = scsi_verify_blk_ioctl(NULL, cmd); |
1548 | 1555 | ||
1556 | if (r == -EAGAIN && !fatal_signal_pending(current)) { | ||
1557 | queue_work(kmultipathd, &m->process_queued_ios); | ||
1558 | msleep(10); | ||
1559 | goto again; | ||
1560 | } | ||
1561 | |||
1549 | return r ? : __blkdev_driver_ioctl(bdev, mode, cmd, arg); | 1562 | return r ? : __blkdev_driver_ioctl(bdev, mode, cmd, arg); |
1550 | } | 1563 | } |
1551 | 1564 | ||
@@ -1643,7 +1656,7 @@ out: | |||
1643 | *---------------------------------------------------------------*/ | 1656 | *---------------------------------------------------------------*/ |
1644 | static struct target_type multipath_target = { | 1657 | static struct target_type multipath_target = { |
1645 | .name = "multipath", | 1658 | .name = "multipath", |
1646 | .version = {1, 3, 0}, | 1659 | .version = {1, 4, 0}, |
1647 | .module = THIS_MODULE, | 1660 | .module = THIS_MODULE, |
1648 | .ctr = multipath_ctr, | 1661 | .ctr = multipath_ctr, |
1649 | .dtr = multipath_dtr, | 1662 | .dtr = multipath_dtr, |