Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 760bf578 authored by Mike Christie's avatar Mike Christie Committed by Nicholas Bellinger
Browse files

target: fix race during implicit transition work flushes



This fixes the following races:

1. core_alua_do_transition_tg_pt could have read
tg_pt_gp_alua_access_state and gone into this if chunk:

if (!explicit &&
        atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state) ==
           ALUA_ACCESS_STATE_TRANSITION) {

and then core_alua_do_transition_tg_pt_work could update the
state. core_alua_do_transition_tg_pt would then only set
tg_pt_gp_alua_pending_state and the tg_pt_gp_alua_access_state would
not get updated with the second calls state.

2. core_alua_do_transition_tg_pt could be setting
tg_pt_gp_transition_complete while the tg_pt_gp_transition_work
is already completing. core_alua_do_transition_tg_pt then waits on the
completion that will never be called.

To handle these issues, we just call flush_work which will return when
core_alua_do_transition_tg_pt_work has completed so there is no need
to do the complete/wait. And, if core_alua_do_transition_tg_pt_work
was running, instead of trying to sneak in the state change, we just
schedule up another core_alua_do_transition_tg_pt_work call.

Note that this does not handle a possible race where there are multiple
threads call core_alua_do_transition_tg_pt at the same time. I think
we need a mutex in target_tg_pt_gp_alua_access_state_store.

Signed-off-by: default avatarMike Christie <mchristi@redhat.com>
Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent 1ca4d4fa
Loading
Loading
Loading
Loading
+1 −9
Original line number Diff line number Diff line
@@ -1079,16 +1079,8 @@ static int core_alua_do_transition_tg_pt(
	/*
	 * Flush any pending transitions
	 */
	if (!explicit && atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state) ==
	    ALUA_ACCESS_STATE_TRANSITION) {
		/* Just in case */
		tg_pt_gp->tg_pt_gp_alua_pending_state = new_state;
		tg_pt_gp->tg_pt_gp_transition_complete = &wait;
	if (!explicit)
		flush_work(&tg_pt_gp->tg_pt_gp_transition_work);
		wait_for_completion(&wait);
		tg_pt_gp->tg_pt_gp_transition_complete = NULL;
		return 0;
	}

	/*
	 * Save the old primary ALUA access state, and set the current state