Pārlūkot izejas kodu

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
Mike Snitzer 9 gadi atpakaļ
vecāks
revīzija
eaf9a7361f
1 mainītis faili ar 7 papildinājumiem un 7 dzēšanām
  1. 7 7
      drivers/md/dm.c

+ 7 - 7
drivers/md/dm.c

@@ -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);
-
-	set_bit(DMF_SUSPENDED_INTERNALLY, &md->flags);
+	(void) __dm_suspend(md, map, suspend_flags, TASK_UNINTERRUPTIBLE,
+			    DMF_SUSPENDED_INTERNALLY);
 
 
 	dm_table_postsuspend_targets(map);
 	dm_table_postsuspend_targets(map);
 }
 }