dm: set DMF_SUSPENDED* _before_ clearing DMF_NOFLUSH_SUSPENDING
Otherwise, there is potential for both DMF_SUSPENDED* and DMF_NOFLUSH_SUSPENDING to not be set during dm_suspend() -- which is definitely _not_ a valid state. This fix, in conjuction with "dm rq: fix the starting and stopping of blk-mq queues", addresses the potential for request-based DM multipath's __multipath_map() to see !dm_noflush_suspending() during suspend. Reported-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com> Cc: stable@vger.kernel.org
This commit is contained in:
parent
7d9595d848
commit
eaf9a7361f
@ -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,
|
|||||||
* 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 @@ retry:
|
|||||||
|
|
||||||
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
|
|||||||
* 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);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user