Commit 374117ad authored by Mike Snitzer's avatar Mike Snitzer

dm mpath: use double checked locking in fast path

Fast-path code biased toward lazy acknowledgement of bit being set
(primarily only for initialization).  Multipath code is very retry
oriented so even if state is missed it'll recover.
Signed-off-by: default avatarMike Snitzer <snitzer@redhat.com>
parent 564dbb13
...@@ -128,6 +128,20 @@ static void queue_if_no_path_timeout_work(struct timer_list *t); ...@@ -128,6 +128,20 @@ static void queue_if_no_path_timeout_work(struct timer_list *t);
#define MPATHF_PG_INIT_REQUIRED 5 /* pg_init needs calling? */ #define MPATHF_PG_INIT_REQUIRED 5 /* pg_init needs calling? */
#define MPATHF_PG_INIT_DELAY_RETRY 6 /* Delay pg_init retry? */ #define MPATHF_PG_INIT_DELAY_RETRY 6 /* Delay pg_init retry? */
static bool mpath_double_check_test_bit(int MPATHF_bit, struct multipath *m)
{
bool r = test_bit(MPATHF_bit, &m->flags);
if (r) {
unsigned long flags;
spin_lock_irqsave(&m->lock, flags);
r = test_bit(MPATHF_bit, &m->flags);
spin_unlock_irqrestore(&m->lock, flags);
}
return r;
}
/*----------------------------------------------- /*-----------------------------------------------
* Allocation routines * Allocation routines
*-----------------------------------------------*/ *-----------------------------------------------*/
...@@ -499,7 +513,7 @@ static int multipath_clone_and_map(struct dm_target *ti, struct request *rq, ...@@ -499,7 +513,7 @@ static int multipath_clone_and_map(struct dm_target *ti, struct request *rq,
/* Do we need to select a new pgpath? */ /* Do we need to select a new pgpath? */
pgpath = READ_ONCE(m->current_pgpath); pgpath = READ_ONCE(m->current_pgpath);
if (!pgpath || !test_bit(MPATHF_QUEUE_IO, &m->flags)) if (!pgpath || !mpath_double_check_test_bit(MPATHF_QUEUE_IO, m))
pgpath = choose_pgpath(m, nr_bytes); pgpath = choose_pgpath(m, nr_bytes);
if (!pgpath) { if (!pgpath) {
...@@ -507,8 +521,8 @@ static int multipath_clone_and_map(struct dm_target *ti, struct request *rq, ...@@ -507,8 +521,8 @@ static int multipath_clone_and_map(struct dm_target *ti, struct request *rq,
return DM_MAPIO_DELAY_REQUEUE; return DM_MAPIO_DELAY_REQUEUE;
dm_report_EIO(m); /* Failed */ dm_report_EIO(m); /* Failed */
return DM_MAPIO_KILL; return DM_MAPIO_KILL;
} else if (test_bit(MPATHF_QUEUE_IO, &m->flags) || } else if (mpath_double_check_test_bit(MPATHF_QUEUE_IO, m) ||
test_bit(MPATHF_PG_INIT_REQUIRED, &m->flags)) { mpath_double_check_test_bit(MPATHF_PG_INIT_REQUIRED, m)) {
pg_init_all_paths(m); pg_init_all_paths(m);
return DM_MAPIO_DELAY_REQUEUE; return DM_MAPIO_DELAY_REQUEUE;
} }
...@@ -598,7 +612,7 @@ static struct pgpath *__map_bio(struct multipath *m, struct bio *bio) ...@@ -598,7 +612,7 @@ static struct pgpath *__map_bio(struct multipath *m, struct bio *bio)
/* Do we need to select a new pgpath? */ /* Do we need to select a new pgpath? */
pgpath = READ_ONCE(m->current_pgpath); pgpath = READ_ONCE(m->current_pgpath);
if (!pgpath || !test_bit(MPATHF_QUEUE_IO, &m->flags)) if (!pgpath || !mpath_double_check_test_bit(MPATHF_QUEUE_IO, m))
pgpath = choose_pgpath(m, bio->bi_iter.bi_size); pgpath = choose_pgpath(m, bio->bi_iter.bi_size);
if (!pgpath) { if (!pgpath) {
...@@ -609,8 +623,8 @@ static struct pgpath *__map_bio(struct multipath *m, struct bio *bio) ...@@ -609,8 +623,8 @@ static struct pgpath *__map_bio(struct multipath *m, struct bio *bio)
} }
spin_unlock_irqrestore(&m->lock, flags); spin_unlock_irqrestore(&m->lock, flags);
} else if (test_bit(MPATHF_QUEUE_IO, &m->flags) || } else if (mpath_double_check_test_bit(MPATHF_QUEUE_IO, m) ||
test_bit(MPATHF_PG_INIT_REQUIRED, &m->flags)) { mpath_double_check_test_bit(MPATHF_PG_INIT_REQUIRED, m)) {
multipath_queue_bio(m, bio); multipath_queue_bio(m, bio);
pg_init_all_paths(m); pg_init_all_paths(m);
return ERR_PTR(-EAGAIN); return ERR_PTR(-EAGAIN);
...@@ -861,7 +875,7 @@ static int setup_scsi_dh(struct block_device *bdev, struct multipath *m, ...@@ -861,7 +875,7 @@ static int setup_scsi_dh(struct block_device *bdev, struct multipath *m,
struct request_queue *q = bdev_get_queue(bdev); struct request_queue *q = bdev_get_queue(bdev);
int r; int r;
if (test_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags)) { if (mpath_double_check_test_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, m)) {
retain: retain:
if (*attached_handler_name) { if (*attached_handler_name) {
/* /*
...@@ -1967,11 +1981,11 @@ static int multipath_prepare_ioctl(struct dm_target *ti, ...@@ -1967,11 +1981,11 @@ static int multipath_prepare_ioctl(struct dm_target *ti,
int r; int r;
pgpath = READ_ONCE(m->current_pgpath); pgpath = READ_ONCE(m->current_pgpath);
if (!pgpath || !test_bit(MPATHF_QUEUE_IO, &m->flags)) if (!pgpath || !mpath_double_check_test_bit(MPATHF_QUEUE_IO, m))
pgpath = choose_pgpath(m, 0); pgpath = choose_pgpath(m, 0);
if (pgpath) { if (pgpath) {
if (!test_bit(MPATHF_QUEUE_IO, &m->flags)) { if (!mpath_double_check_test_bit(MPATHF_QUEUE_IO, m)) {
*bdev = pgpath->path.dev->bdev; *bdev = pgpath->path.dev->bdev;
r = 0; r = 0;
} else { } else {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment