Commit d268675c authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'dm-4.8-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm

Pull device mapper fixes from Mike Snitzer:

 - a stable dm-flakey fix to error read IO during the 'down_interval'

 - a DM core suspend fix to establish the SUSPENDED flag before dropping
   the SUSPENDING flag

 - a blk-mq request-based DM (dm-mq) dm_stop_queue() fix to properly
   stop the blk-mq hw_queues (and cancel pending requeue work); also
   set/clear QUEUE_FLAG_STOPPED when stopping/starting the dm-mq
   request_queue.

 - a DM multipath fix to harden locking of in-core state flags in the
   face of concurrent access while handling path failures under heavy
   IO.

 - a few small DM raid fixes to edge cases caught with further testing.

* tag 'dm-4.8-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm:
  dm raid: fix use of wrong status char during resynchronization
  dm raid: constructor fails on non-zero incompat_features
  dm raid: fix processing of max_recovery_rate constructor flag
  dm: set DMF_SUSPENDED* _before_ clearing DMF_NOFLUSH_SUSPENDING
  dm rq: fix the starting and stopping of blk-mq queues
  dm mpath: add locking to multipath_resume and must_push_back
  dm flakey: error READ bios during the down_interval
parents fff648da 2a034ec1
...@@ -289,10 +289,16 @@ static int flakey_map(struct dm_target *ti, struct bio *bio) ...@@ -289,10 +289,16 @@ static int flakey_map(struct dm_target *ti, struct bio *bio)
pb->bio_submitted = true; pb->bio_submitted = true;
/* /*
* Map reads as normal. * Map reads as normal only if corrupt_bio_byte set.
*/ */
if (bio_data_dir(bio) == READ) if (bio_data_dir(bio) == READ) {
goto map_bio; /* If flags were specified, only corrupt those that match. */
if (fc->corrupt_bio_byte && (fc->corrupt_bio_rw == READ) &&
all_corrupt_bio_flags_match(bio, fc))
goto map_bio;
else
return -EIO;
}
/* /*
* Drop writes? * Drop writes?
...@@ -330,12 +336,13 @@ static int flakey_end_io(struct dm_target *ti, struct bio *bio, int error) ...@@ -330,12 +336,13 @@ static int flakey_end_io(struct dm_target *ti, struct bio *bio, int error)
/* /*
* Corrupt successful READs while in down state. * Corrupt successful READs while in down state.
* If flags were specified, only corrupt those that match.
*/ */
if (fc->corrupt_bio_byte && !error && pb->bio_submitted && if (!error && pb->bio_submitted && (bio_data_dir(bio) == READ)) {
(bio_data_dir(bio) == READ) && (fc->corrupt_bio_rw == READ) && if (fc->corrupt_bio_byte)
all_corrupt_bio_flags_match(bio, fc)) corrupt_bio_data(bio, fc);
corrupt_bio_data(bio, fc); else
return -EIO;
}
return error; return error;
} }
......
...@@ -507,13 +507,27 @@ static bool __must_push_back(struct multipath *m) ...@@ -507,13 +507,27 @@ static bool __must_push_back(struct multipath *m)
static bool must_push_back_rq(struct multipath *m) static bool must_push_back_rq(struct multipath *m)
{ {
return (test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags) || bool r;
__must_push_back(m)); unsigned long flags;
spin_lock_irqsave(&m->lock, flags);
r = (test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags) ||
__must_push_back(m));
spin_unlock_irqrestore(&m->lock, flags);
return r;
} }
static bool must_push_back_bio(struct multipath *m) static bool must_push_back_bio(struct multipath *m)
{ {
return __must_push_back(m); bool r;
unsigned long flags;
spin_lock_irqsave(&m->lock, flags);
r = __must_push_back(m);
spin_unlock_irqrestore(&m->lock, flags);
return r;
} }
/* /*
...@@ -1680,12 +1694,14 @@ static void multipath_postsuspend(struct dm_target *ti) ...@@ -1680,12 +1694,14 @@ static void multipath_postsuspend(struct dm_target *ti)
static void multipath_resume(struct dm_target *ti) static void multipath_resume(struct dm_target *ti)
{ {
struct multipath *m = ti->private; struct multipath *m = ti->private;
unsigned long flags;
spin_lock_irqsave(&m->lock, flags);
if (test_bit(MPATHF_SAVED_QUEUE_IF_NO_PATH, &m->flags)) if (test_bit(MPATHF_SAVED_QUEUE_IF_NO_PATH, &m->flags))
set_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags); set_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags);
else else
clear_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags); clear_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags);
smp_mb__after_atomic(); spin_unlock_irqrestore(&m->lock, flags);
} }
/* /*
......
...@@ -1270,7 +1270,7 @@ static int parse_raid_params(struct raid_set *rs, struct dm_arg_set *as, ...@@ -1270,7 +1270,7 @@ static int parse_raid_params(struct raid_set *rs, struct dm_arg_set *as,
} }
rs->md.sync_speed_min = (int)value; rs->md.sync_speed_min = (int)value;
} else if (!strcasecmp(key, dm_raid_arg_name_by_flag(CTR_FLAG_MAX_RECOVERY_RATE))) { } else if (!strcasecmp(key, dm_raid_arg_name_by_flag(CTR_FLAG_MAX_RECOVERY_RATE))) {
if (test_and_set_bit(__CTR_FLAG_MIN_RECOVERY_RATE, &rs->ctr_flags)) { if (test_and_set_bit(__CTR_FLAG_MAX_RECOVERY_RATE, &rs->ctr_flags)) {
rs->ti->error = "Only one max_recovery_rate argument pair allowed"; rs->ti->error = "Only one max_recovery_rate argument pair allowed";
return -EINVAL; return -EINVAL;
} }
...@@ -1960,6 +1960,7 @@ static void super_sync(struct mddev *mddev, struct md_rdev *rdev) ...@@ -1960,6 +1960,7 @@ static void super_sync(struct mddev *mddev, struct md_rdev *rdev)
sb->data_offset = cpu_to_le64(rdev->data_offset); sb->data_offset = cpu_to_le64(rdev->data_offset);
sb->new_data_offset = cpu_to_le64(rdev->new_data_offset); sb->new_data_offset = cpu_to_le64(rdev->new_data_offset);
sb->sectors = cpu_to_le64(rdev->sectors); sb->sectors = cpu_to_le64(rdev->sectors);
sb->incompat_features = cpu_to_le32(0);
/* Zero out the rest of the payload after the size of the superblock */ /* Zero out the rest of the payload after the size of the superblock */
memset(sb + 1, 0, rdev->sb_size - sizeof(*sb)); memset(sb + 1, 0, rdev->sb_size - sizeof(*sb));
...@@ -3577,7 +3578,6 @@ static int raid_preresume(struct dm_target *ti) ...@@ -3577,7 +3578,6 @@ static int raid_preresume(struct dm_target *ti)
/* Be prepared for mddev_resume() in raid_resume() */ /* Be prepared for mddev_resume() in raid_resume() */
set_bit(MD_RECOVERY_FROZEN, &mddev->recovery); set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
if (mddev->recovery_cp && mddev->recovery_cp < MaxSector) { if (mddev->recovery_cp && mddev->recovery_cp < MaxSector) {
set_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
set_bit(MD_RECOVERY_SYNC, &mddev->recovery); set_bit(MD_RECOVERY_SYNC, &mddev->recovery);
mddev->resync_min = mddev->recovery_cp; mddev->resync_min = mddev->recovery_cp;
} }
......
...@@ -78,6 +78,7 @@ void dm_start_queue(struct request_queue *q) ...@@ -78,6 +78,7 @@ void dm_start_queue(struct request_queue *q)
if (!q->mq_ops) if (!q->mq_ops)
dm_old_start_queue(q); dm_old_start_queue(q);
else { else {
queue_flag_clear_unlocked(QUEUE_FLAG_STOPPED, q);
blk_mq_start_stopped_hw_queues(q, true); blk_mq_start_stopped_hw_queues(q, true);
blk_mq_kick_requeue_list(q); blk_mq_kick_requeue_list(q);
} }
...@@ -101,8 +102,14 @@ void dm_stop_queue(struct request_queue *q) ...@@ -101,8 +102,14 @@ void dm_stop_queue(struct request_queue *q)
{ {
if (!q->mq_ops) if (!q->mq_ops)
dm_old_stop_queue(q); dm_old_stop_queue(q);
else else {
spin_lock_irq(q->queue_lock);
queue_flag_set(QUEUE_FLAG_STOPPED, q);
spin_unlock_irq(q->queue_lock);
blk_mq_cancel_requeue_work(q);
blk_mq_stop_hw_queues(q); blk_mq_stop_hw_queues(q);
}
} }
static struct dm_rq_target_io *alloc_old_rq_tio(struct mapped_device *md, static struct dm_rq_target_io *alloc_old_rq_tio(struct mapped_device *md,
...@@ -864,6 +871,17 @@ static int dm_mq_queue_rq(struct blk_mq_hw_ctx *hctx, ...@@ -864,6 +871,17 @@ static int dm_mq_queue_rq(struct blk_mq_hw_ctx *hctx,
dm_put_live_table(md, srcu_idx); dm_put_live_table(md, srcu_idx);
} }
/*
* On suspend dm_stop_queue() handles stopping the blk-mq
* request_queue BUT: even though the hw_queues are marked
* BLK_MQ_S_STOPPED at that point there is still a race that
* is allowing block/blk-mq.c to call ->queue_rq against a
* hctx that it really shouldn't. The following check guards
* against this rarity (albeit _not_ race-free).
*/
if (unlikely(test_bit(BLK_MQ_S_STOPPED, &hctx->state)))
return BLK_MQ_RQ_QUEUE_BUSY;
if (ti->type->busy && ti->type->busy(ti)) if (ti->type->busy && ti->type->busy(ti))
return BLK_MQ_RQ_QUEUE_BUSY; return BLK_MQ_RQ_QUEUE_BUSY;
......
...@@ -2082,7 +2082,8 @@ static void unlock_fs(struct mapped_device *md) ...@@ -2082,7 +2082,8 @@ static void unlock_fs(struct mapped_device *md)
* Caller must hold md->suspend_lock * Caller must hold md->suspend_lock
*/ */
static int __dm_suspend(struct mapped_device *md, struct dm_table *map, static int __dm_suspend(struct mapped_device *md, struct dm_table *map,
unsigned suspend_flags, int interruptible) unsigned suspend_flags, int interruptible,
int dmf_suspended_flag)
{ {
bool do_lockfs = suspend_flags & DM_SUSPEND_LOCKFS_FLAG; bool do_lockfs = suspend_flags & DM_SUSPEND_LOCKFS_FLAG;
bool noflush = suspend_flags & DM_SUSPEND_NOFLUSH_FLAG; bool noflush = suspend_flags & DM_SUSPEND_NOFLUSH_FLAG;
...@@ -2149,6 +2150,8 @@ static int __dm_suspend(struct mapped_device *md, struct dm_table *map, ...@@ -2149,6 +2150,8 @@ static int __dm_suspend(struct mapped_device *md, struct dm_table *map,
* to finish. * to finish.
*/ */
r = dm_wait_for_completion(md, interruptible); r = dm_wait_for_completion(md, interruptible);
if (!r)
set_bit(dmf_suspended_flag, &md->flags);
if (noflush) if (noflush)
clear_bit(DMF_NOFLUSH_SUSPENDING, &md->flags); clear_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);
...@@ -2210,12 +2213,10 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags) ...@@ -2210,12 +2213,10 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
map = rcu_dereference_protected(md->map, lockdep_is_held(&md->suspend_lock)); map = rcu_dereference_protected(md->map, lockdep_is_held(&md->suspend_lock));
r = __dm_suspend(md, map, suspend_flags, TASK_INTERRUPTIBLE); r = __dm_suspend(md, map, suspend_flags, TASK_INTERRUPTIBLE, DMF_SUSPENDED);
if (r) if (r)
goto out_unlock; goto out_unlock;
set_bit(DMF_SUSPENDED, &md->flags);
dm_table_postsuspend_targets(map); dm_table_postsuspend_targets(map);
out_unlock: out_unlock:
...@@ -2309,9 +2310,8 @@ static void __dm_internal_suspend(struct mapped_device *md, unsigned suspend_fla ...@@ -2309,9 +2310,8 @@ static void __dm_internal_suspend(struct mapped_device *md, unsigned suspend_fla
* would require changing .presuspend to return an error -- avoid this * would require changing .presuspend to return an error -- avoid this
* until there is a need for more elaborate variants of internal suspend. * until there is a need for more elaborate variants of internal suspend.
*/ */
(void) __dm_suspend(md, map, suspend_flags, TASK_UNINTERRUPTIBLE); (void) __dm_suspend(md, map, suspend_flags, TASK_UNINTERRUPTIBLE,
DMF_SUSPENDED_INTERNALLY);
set_bit(DMF_SUSPENDED_INTERNALLY, &md->flags);
dm_table_postsuspend_targets(map); dm_table_postsuspend_targets(map);
} }
......
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