Merge tag 'for-5.9/dm-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm
Pull device mapper updates from Mike Snitzer: - DM multipath locking fixes around m->flags tests and improvements to bio-based code so that it follows patterns established by request-based code. - Request-based DM core improvement to eliminate unnecessary call to blk_mq_queue_stopped(). - Add "panic_on_corruption" error handling mode to DM verity target. - DM bufio fix to to perform buffer cleanup from a workqueue rather than wait for IO in reclaim context from shrinker. - DM crypt improvement to optionally avoid async processing via workqueues for reads and/or writes -- via "no_read_workqueue" and "no_write_workqueue" features. This more direct IO processing improves latency and throughput with faster storage. Avoiding workqueue IO submission for writes (DM_CRYPT_NO_WRITE_WORKQUEUE) is a requirement for adding zoned block device support to DM crypt. - Add zoned block device support to DM crypt. Makes use of DM_CRYPT_NO_WRITE_WORKQUEUE and a new optional feature (DM_CRYPT_WRITE_INLINE) that allows write completion to wait for encryption to complete. This allows write ordering to be preserved, which is needed for zoned block devices. - Fix DM ebs target's check for REQ_OP_FLUSH. - Fix DM core's report zones support to not report more zones than were requested. - A few small compiler warning fixes. - DM dust improvements to return output directly to the user rather than require they scrape the system log for output. * tag 'for-5.9/dm-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm: dm: don't call report zones for more than the user requested dm ebs: Fix incorrect checking for REQ_OP_FLUSH dm init: Set file local variable static dm ioctl: Fix compilation warning dm raid: Remove empty if statement dm verity: Fix compilation warning dm crypt: Enable zoned block device support dm crypt: add flags to optionally bypass kcryptd workqueues dm bufio: do buffer cleanup from a workqueue dm rq: don't call blk_mq_queue_stopped() in dm_stop_queue() dm dust: add interface to list all badblocks dm dust: report some message results directly back to user dm verity: add "panic_on_corruption" error handling mode dm mpath: use double checked locking in fast path dm mpath: rename current_pgpath to pgpath in multipath_prepare_ioctl dm mpath: rework __map_bio() dm mpath: factor out multipath_queue_bio dm mpath: push locking down to must_push_back_rq() dm mpath: take m->lock spinlock when testing QUEUE_IF_NO_PATH dm mpath: changes from initial m->flags locking audit
This commit is contained in:
@@ -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_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
|
||||
*-----------------------------------------------*/
|
||||
@@ -335,6 +349,8 @@ static int pg_init_all_paths(struct multipath *m)
|
||||
|
||||
static void __switch_pg(struct multipath *m, struct priority_group *pg)
|
||||
{
|
||||
lockdep_assert_held(&m->lock);
|
||||
|
||||
m->current_pg = pg;
|
||||
|
||||
/* Must we initialise the PG first, and queue I/O till it's ready? */
|
||||
@@ -382,7 +398,9 @@ static struct pgpath *choose_pgpath(struct multipath *m, size_t nr_bytes)
|
||||
unsigned bypassed = 1;
|
||||
|
||||
if (!atomic_read(&m->nr_valid_paths)) {
|
||||
spin_lock_irqsave(&m->lock, flags);
|
||||
clear_bit(MPATHF_QUEUE_IO, &m->flags);
|
||||
spin_unlock_irqrestore(&m->lock, flags);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
@@ -422,8 +440,11 @@ check_current_pg:
|
||||
continue;
|
||||
pgpath = choose_path_in_pg(m, pg, nr_bytes);
|
||||
if (!IS_ERR_OR_NULL(pgpath)) {
|
||||
if (!bypassed)
|
||||
if (!bypassed) {
|
||||
spin_lock_irqsave(&m->lock, flags);
|
||||
set_bit(MPATHF_PG_INIT_DELAY_RETRY, &m->flags);
|
||||
spin_unlock_irqrestore(&m->lock, flags);
|
||||
}
|
||||
return pgpath;
|
||||
}
|
||||
}
|
||||
@@ -465,7 +486,14 @@ static bool __must_push_back(struct multipath *m)
|
||||
|
||||
static bool must_push_back_rq(struct multipath *m)
|
||||
{
|
||||
return test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags) || __must_push_back(m);
|
||||
unsigned long flags;
|
||||
bool ret;
|
||||
|
||||
spin_lock_irqsave(&m->lock, flags);
|
||||
ret = (test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags) || __must_push_back(m));
|
||||
spin_unlock_irqrestore(&m->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -485,7 +513,7 @@ static int multipath_clone_and_map(struct dm_target *ti, struct request *rq,
|
||||
|
||||
/* Do we need to select a new 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);
|
||||
|
||||
if (!pgpath) {
|
||||
@@ -493,8 +521,8 @@ static int multipath_clone_and_map(struct dm_target *ti, struct request *rq,
|
||||
return DM_MAPIO_DELAY_REQUEUE;
|
||||
dm_report_EIO(m); /* Failed */
|
||||
return DM_MAPIO_KILL;
|
||||
} else if (test_bit(MPATHF_QUEUE_IO, &m->flags) ||
|
||||
test_bit(MPATHF_PG_INIT_REQUIRED, &m->flags)) {
|
||||
} else if (mpath_double_check_test_bit(MPATHF_QUEUE_IO, m) ||
|
||||
mpath_double_check_test_bit(MPATHF_PG_INIT_REQUIRED, m)) {
|
||||
pg_init_all_paths(m);
|
||||
return DM_MAPIO_DELAY_REQUEUE;
|
||||
}
|
||||
@@ -560,33 +588,45 @@ static void multipath_release_clone(struct request *clone,
|
||||
* Map cloned bios (bio-based multipath)
|
||||
*/
|
||||
|
||||
static void __multipath_queue_bio(struct multipath *m, struct bio *bio)
|
||||
{
|
||||
/* Queue for the daemon to resubmit */
|
||||
bio_list_add(&m->queued_bios, bio);
|
||||
if (!test_bit(MPATHF_QUEUE_IO, &m->flags))
|
||||
queue_work(kmultipathd, &m->process_queued_bios);
|
||||
}
|
||||
|
||||
static void multipath_queue_bio(struct multipath *m, struct bio *bio)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&m->lock, flags);
|
||||
__multipath_queue_bio(m, bio);
|
||||
spin_unlock_irqrestore(&m->lock, flags);
|
||||
}
|
||||
|
||||
static struct pgpath *__map_bio(struct multipath *m, struct bio *bio)
|
||||
{
|
||||
struct pgpath *pgpath;
|
||||
unsigned long flags;
|
||||
bool queue_io;
|
||||
|
||||
/* Do we need to select a new 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);
|
||||
|
||||
/* MPATHF_QUEUE_IO might have been cleared by choose_pgpath. */
|
||||
queue_io = test_bit(MPATHF_QUEUE_IO, &m->flags);
|
||||
|
||||
if ((pgpath && queue_io) ||
|
||||
(!pgpath && test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags))) {
|
||||
/* Queue for the daemon to resubmit */
|
||||
if (!pgpath) {
|
||||
spin_lock_irqsave(&m->lock, flags);
|
||||
bio_list_add(&m->queued_bios, bio);
|
||||
if (test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags)) {
|
||||
__multipath_queue_bio(m, bio);
|
||||
pgpath = ERR_PTR(-EAGAIN);
|
||||
}
|
||||
spin_unlock_irqrestore(&m->lock, flags);
|
||||
|
||||
/* PG_INIT_REQUIRED cannot be set without QUEUE_IO */
|
||||
if (queue_io || test_bit(MPATHF_PG_INIT_REQUIRED, &m->flags))
|
||||
pg_init_all_paths(m);
|
||||
else if (!queue_io)
|
||||
queue_work(kmultipathd, &m->process_queued_bios);
|
||||
|
||||
} else if (mpath_double_check_test_bit(MPATHF_QUEUE_IO, m) ||
|
||||
mpath_double_check_test_bit(MPATHF_PG_INIT_REQUIRED, m)) {
|
||||
multipath_queue_bio(m, bio);
|
||||
pg_init_all_paths(m);
|
||||
return ERR_PTR(-EAGAIN);
|
||||
}
|
||||
|
||||
@@ -835,7 +875,7 @@ static int setup_scsi_dh(struct block_device *bdev, struct multipath *m,
|
||||
struct request_queue *q = bdev_get_queue(bdev);
|
||||
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:
|
||||
if (*attached_handler_name) {
|
||||
/*
|
||||
@@ -1614,7 +1654,7 @@ static int multipath_end_io(struct dm_target *ti, struct request *clone,
|
||||
if (pgpath)
|
||||
fail_path(pgpath);
|
||||
|
||||
if (atomic_read(&m->nr_valid_paths) == 0 &&
|
||||
if (!atomic_read(&m->nr_valid_paths) &&
|
||||
!must_push_back_rq(m)) {
|
||||
if (error == BLK_STS_IOERR)
|
||||
dm_report_EIO(m);
|
||||
@@ -1649,23 +1689,22 @@ static int multipath_end_io_bio(struct dm_target *ti, struct bio *clone,
|
||||
if (pgpath)
|
||||
fail_path(pgpath);
|
||||
|
||||
if (atomic_read(&m->nr_valid_paths) == 0 &&
|
||||
!test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags)) {
|
||||
if (__must_push_back(m)) {
|
||||
r = DM_ENDIO_REQUEUE;
|
||||
} else {
|
||||
dm_report_EIO(m);
|
||||
*error = BLK_STS_IOERR;
|
||||
if (!atomic_read(&m->nr_valid_paths)) {
|
||||
spin_lock_irqsave(&m->lock, flags);
|
||||
if (!test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags)) {
|
||||
if (__must_push_back(m)) {
|
||||
r = DM_ENDIO_REQUEUE;
|
||||
} else {
|
||||
dm_report_EIO(m);
|
||||
*error = BLK_STS_IOERR;
|
||||
}
|
||||
spin_unlock_irqrestore(&m->lock, flags);
|
||||
goto done;
|
||||
}
|
||||
goto done;
|
||||
spin_unlock_irqrestore(&m->lock, flags);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&m->lock, flags);
|
||||
bio_list_add(&m->queued_bios, clone);
|
||||
spin_unlock_irqrestore(&m->lock, flags);
|
||||
if (!test_bit(MPATHF_QUEUE_IO, &m->flags))
|
||||
queue_work(kmultipathd, &m->process_queued_bios);
|
||||
|
||||
multipath_queue_bio(m, clone);
|
||||
r = DM_ENDIO_INCOMPLETE;
|
||||
done:
|
||||
if (pgpath) {
|
||||
@@ -1937,16 +1976,17 @@ static int multipath_prepare_ioctl(struct dm_target *ti,
|
||||
struct block_device **bdev)
|
||||
{
|
||||
struct multipath *m = ti->private;
|
||||
struct pgpath *current_pgpath;
|
||||
struct pgpath *pgpath;
|
||||
unsigned long flags;
|
||||
int r;
|
||||
|
||||
current_pgpath = READ_ONCE(m->current_pgpath);
|
||||
if (!current_pgpath || !test_bit(MPATHF_QUEUE_IO, &m->flags))
|
||||
current_pgpath = choose_pgpath(m, 0);
|
||||
pgpath = READ_ONCE(m->current_pgpath);
|
||||
if (!pgpath || !mpath_double_check_test_bit(MPATHF_QUEUE_IO, m))
|
||||
pgpath = choose_pgpath(m, 0);
|
||||
|
||||
if (current_pgpath) {
|
||||
if (!test_bit(MPATHF_QUEUE_IO, &m->flags)) {
|
||||
*bdev = current_pgpath->path.dev->bdev;
|
||||
if (pgpath) {
|
||||
if (!mpath_double_check_test_bit(MPATHF_QUEUE_IO, m)) {
|
||||
*bdev = pgpath->path.dev->bdev;
|
||||
r = 0;
|
||||
} else {
|
||||
/* pg_init has not started or completed */
|
||||
@@ -1954,10 +1994,11 @@ static int multipath_prepare_ioctl(struct dm_target *ti,
|
||||
}
|
||||
} else {
|
||||
/* No path is available */
|
||||
r = -EIO;
|
||||
spin_lock_irqsave(&m->lock, flags);
|
||||
if (test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags))
|
||||
r = -ENOTCONN;
|
||||
else
|
||||
r = -EIO;
|
||||
spin_unlock_irqrestore(&m->lock, flags);
|
||||
}
|
||||
|
||||
if (r == -ENOTCONN) {
|
||||
@@ -1965,8 +2006,10 @@ static int multipath_prepare_ioctl(struct dm_target *ti,
|
||||
/* Path status changed, redo selection */
|
||||
(void) choose_pgpath(m, 0);
|
||||
}
|
||||
spin_lock_irqsave(&m->lock, flags);
|
||||
if (test_bit(MPATHF_PG_INIT_REQUIRED, &m->flags))
|
||||
pg_init_all_paths(m);
|
||||
(void) __pg_init_all_paths(m);
|
||||
spin_unlock_irqrestore(&m->lock, flags);
|
||||
dm_table_run_md_queue_async(m->ti->table);
|
||||
process_queued_io_list(m);
|
||||
}
|
||||
@@ -2026,8 +2069,15 @@ static int multipath_busy(struct dm_target *ti)
|
||||
return true;
|
||||
|
||||
/* no paths available, for blk-mq: rely on IO mapping to delay requeue */
|
||||
if (!atomic_read(&m->nr_valid_paths) && test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags))
|
||||
return (m->queue_mode != DM_TYPE_REQUEST_BASED);
|
||||
if (!atomic_read(&m->nr_valid_paths)) {
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&m->lock, flags);
|
||||
if (test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags)) {
|
||||
spin_unlock_irqrestore(&m->lock, flags);
|
||||
return (m->queue_mode != DM_TYPE_REQUEST_BASED);
|
||||
}
|
||||
spin_unlock_irqrestore(&m->lock, flags);
|
||||
}
|
||||
|
||||
/* Guess which priority_group will be used at next mapping time */
|
||||
pg = READ_ONCE(m->current_pg);
|
||||
|
Reference in New Issue
Block a user