Skip to content

Commit c322ee9

Browse files
committed
dm mpath: fix racey management of PG initialization
Commit 935fcc5 ("dm mpath: only flush workqueue when needed") changed flush_multipath_work() to avoid needless workqueue flushing (of a multipath global workqueue). But that change didn't realize the surrounding flush_multipath_work() code should also only run if 'pg_init_in_progress' is set. Fix this by only doing all of flush_multipath_work()'s PG init related work if 'pg_init_in_progress' is set. Otherwise multipath_wait_for_pg_init_completion() will run unconditionally but the preceeding flush_workqueue(kmpath_handlerd) may not. This could lead to deadlock (though only if kmpath_handlerd never runs a corresponding work to decrement 'pg_init_in_progress'). It could also be, though highly unlikely, that the kmpath_handlerd work that does PG init completes before 'pg_init_in_progress' is set, and then an intervening DM table reload's multipath_postsuspend() triggers flush_multipath_work(). Fixes: 935fcc5 ("dm mpath: only flush workqueue when needed") Cc: stable@vger.kernel.org Reported-by: Ben Marzinski <bmarzins@redhat.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com>
1 parent f9e040e commit c322ee9

1 file changed

Lines changed: 15 additions & 7 deletions

File tree

drivers/md/dm-mpath.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1287,17 +1287,25 @@ static void multipath_wait_for_pg_init_completion(struct multipath *m)
12871287
static void flush_multipath_work(struct multipath *m)
12881288
{
12891289
if (m->hw_handler_name) {
1290-
set_bit(MPATHF_PG_INIT_DISABLED, &m->flags);
1291-
smp_mb__after_atomic();
1290+
unsigned long flags;
1291+
1292+
if (!atomic_read(&m->pg_init_in_progress))
1293+
goto skip;
1294+
1295+
spin_lock_irqsave(&m->lock, flags);
1296+
if (atomic_read(&m->pg_init_in_progress) &&
1297+
!test_and_set_bit(MPATHF_PG_INIT_DISABLED, &m->flags)) {
1298+
spin_unlock_irqrestore(&m->lock, flags);
12921299

1293-
if (atomic_read(&m->pg_init_in_progress))
12941300
flush_workqueue(kmpath_handlerd);
1295-
multipath_wait_for_pg_init_completion(m);
1301+
multipath_wait_for_pg_init_completion(m);
12961302

1297-
clear_bit(MPATHF_PG_INIT_DISABLED, &m->flags);
1298-
smp_mb__after_atomic();
1303+
spin_lock_irqsave(&m->lock, flags);
1304+
clear_bit(MPATHF_PG_INIT_DISABLED, &m->flags);
1305+
}
1306+
spin_unlock_irqrestore(&m->lock, flags);
12991307
}
1300-
1308+
skip:
13011309
if (m->queue_mode == DM_TYPE_BIO_BASED)
13021310
flush_work(&m->process_queued_bios);
13031311
flush_work(&m->trigger_event);

0 commit comments

Comments
 (0)